非常教程

Ruby 2.4参考手册

IO

IO

Parent:ObjectIncluded modules:File::Constants, Enumerable

期望库加入IO实例方法,对tcl的期望扩展做类似的操作。

为了使用这种方法,你必须要求:

require 'expect'

请看使用期望。

IO类是Ruby中所有输入和输出的基础。I/O流可能是双工的(即双向的),因此可能会使用多个本地操作系统流。

本节中的许多示例都使用File类,这是IO的唯一标准子类。这两个班级密切相关。像File类一样,来自IO的Socket库子类(如TCPSocket或UDPSocket)。

Kernel#open方法可以为这些类型的参数创建一个IO(或File)对象:

  • 一个普通的字符串表示一个适合底层操作系统的文件名。
  • 一个以字符开始的字符串"|"表示一个子进程。跟在该字符串后面的字符串的其余部分"|"被调用为具有连接到它的相应输入/输出通道的进程。
  • 等于的字符串"|-"将创建另一个Ruby实例作为子进程.IO可以用不同的文件模式(只读,只写)和适当的转换编码打开。

请参阅:新的这些选项。

有关上述各种命令格式的详细信息,请参阅Kernel#open.::popen,Open3库或Process#spawn也可用于通过IO与子进程通信。

Ruby将尽可能在不同操作系统约定之间转换路径名。例如,在Windows系统上,文件"/gumby/ruby/test.rb"名将被打开为"\gumby\ruby\test.rb"。在Ruby字符串中指定Windows风格的文件名时,请记住要转义反斜杠:

"C:\\gumby\\ruby\\test.rb"

我们的示例将使用Unix风格的正斜杠; File:: ALT_SEPARATOR可用于获取特定于平台的分隔符。全局常量ARGF(也可作为$<)提供了一个IO类流,它允许访问命令行中提到的所有文件(如果没有提到文件,则为STDIN) )。

提供ARGF#路径及其别名ARGF#文件名以访问当前正在读取的文件的名称.io/console io/console扩展提供了与控制台交互的方法。可以从::console或standard input/output/error IO对象访问控制台。要求io/console添加以下方法:

  • ::console
  • #raw
  • #raw!
  • #cooked
  • #cooked!
  • #getch
  • #echo=
  • #echo?
  • #noecho
  • #winsize
  • #winsize=
  • #iflush
  • #ioflush
  • #oflush

示例

require 'io/console'
rows, columns = $stdout.winsize
puts "Your screen is #{columns} wide and #{rows} tall"

常量

EWOULDBLOCKWaitReadable

EAGAINWaitReadable

EWOULDBLOCKWaitWritable

EAGAINWaitWritable

SEEK_CUR

从当前位置设置I/O位置

SEEK_DATA

将I/O位置设置为包含数据的下一个位置

SEEK_END

从最后设置I/O位置

SEEK_HOLE

将I/O位置设置到下一个孔

SEEK_SET

从一开始就设置I/O位置

公共类方法

binread(name, [length [, offset]] ) → string

打开文件,可选择查找给定的偏移量,然后返回长度字节(默认为文件的其余部分)。binread确保文件在返回之前关闭。开放模式将是“rb:ASCII-8BIT”。

IO.binread("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
IO.binread("testfile", 20)       #=> "This is line one\nThi"
IO.binread("testfile", 20, 10)   #=> "ne one\nThis is line "
               static VALUE
rb_io_s_binread(int argc, VALUE *argv, VALUE io)
{
    VALUE offset;
    struct foreach_arg arg;

    rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
    FilePathValue(argv[0]);
    arg.io = rb_io_open(argv[0], rb_str_new_cstr("rb:ASCII-8BIT"), Qnil, Qnil);
    if (NIL_P(arg.io)) return Qnil;
    arg.argv = argv+1;
    arg.argc = (argc > 1) ? 1 : 0;
    if (!NIL_P(offset)) {
        struct seek_arg sarg;
        int state = 0;
        sarg.io = arg.io;
        sarg.offset = offset;
        sarg.mode = SEEK_SET;
        rb_protect(seek_before_access, (VALUE)&sarg, &state);
        if (state) {
            rb_io_close(arg.io);
            rb_jump_tag(state);
        }
    }
    return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}

binwrite(name, string, [offset] ) => fixnum

binwrite(name, string, [offset], open_args ) => fixnum

IO.write以二进制模式和ASCII-8BIT编码打开文件(“wb:ASCII-8BIT”)相同。

               static VALUE
rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
{
    return io_s_write(argc, argv, 1);
}

copy_stream(src, dst)

copy_stream(src, dst, copy_length)

copy_stream(src, dst, copy_length, src_offset)

:: copy_stream将src复制 到dstsrcdst是文件名或IO。

该方法返回复制的字节数。

如果未指定可选参数,则副本的起始位置是文件名的开头或IO的当前文件偏移量。该副本的结束位置是文件的结尾。

如果copy_length给出,不超过copy_length字节被复制。

如果给出了src_offset,它指定了复制的开始位置。

当指定src_offset并且src是IO时,::copy_stream不会移动当前文件偏移量。

 static VALUE
rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
{
    VALUE src, dst, length, src_offset;
    struct copy_stream_struct st;

    MEMZERO(&st, struct copy_stream_struct, 1);

    rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);

    st.src = src;
    st.dst = dst;

    if (NIL_P(length))
        st.copy_length = (off_t)-1;
    else
        st.copy_length = NUM2OFFT(length);

    if (NIL_P(src_offset))
        st.src_offset = (off_t)-1;
    else
        st.src_offset = NUM2OFFT(src_offset);

    rb_fd_init(&st.fds);
    rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);

    return OFFT2NUM(st.total);
}

for_fd(fd, mode [, opt]) → io

IO.new的同义词。

               static VALUE
rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
{
    VALUE io = rb_obj_alloc(klass);
    rb_io_initialize(argc, argv, io);
    return io;
}

foreach(name, sep=$/ [, open_args]) {|line| block } → nil

foreach(name, limit [, open_args]) {|line| block } → nil

foreach(name, sep, limit [, open_args]) {|line| block } → nil

foreach(...) → an_enumerator

执行指定I/O端口中每行的块,其中行由sep分隔。

如果没有给出块,则返回一个枚举器。

IO.foreach("testfile") {|x| print "GOT ", x }

生成:

GOT This is line one
GOT This is line two
GOT This is line three
GOT And so on...

如果最后一个参数是散列,则它是要打开的关键字参数。请参阅IO.read详细信息。

               static VALUE
rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
{
    VALUE opt;
    int orig_argc = argc;
    struct foreach_arg arg;

    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
    RETURN_ENUMERATOR(self, orig_argc, argv);
    open_key_args(argc, argv, opt, &arg);
    if (NIL_P(arg.io)) return Qnil;
    return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
}

new(fd [, mode] [, opt]) → io

为给定的整数文件描述符和字符串返回一个新的IO对象(一个流)。 可用于以更可读的方式指定部分。另见:: sysopen和:: for_fd。fdmodeoptmode

:: new由各种File和IO打开方法调用,如:: open,Kernel#open和File.open。

Open Mode

mode是整数,它必须是在File :: Constants (File::RDONLY,+ File :: WRONLY | File :: CREAT +)中定义的模式的组合。有关更多信息,请参见open(2)手册页。

mode是一个字符串,它必须是以下形式之一:

fmode
fmode ":" ext_enc
fmode ":" ext_enc ":" int_enc
fmode ":" "BOM|UTF-*"

fmode是一个IO打开模式串,ext_enc是外部编码的IO和int_enc是内部编码。

IO Open Mode

Ruby允许以下开放模式:

“r”只读,从文件开始(默认模式)开始。

“r +”是可读写的,从文件开始处开始。

“w”只写,截断现有文件
     以零长度或创建一个新的文件写入。

“w +”是可读写的,将现有文件截断为零
     或创建一个新的文件进行读写。

“a”只写,每个写入调用都会在文件结尾附加数据。
     如果文件不存在,则创建一个用于写入的新文件。

“a +”是可读写的,每次写入调用都会在文件结尾处追加数据。
     创建一个新的文件来读写文件
     不存在。

以下模式必须单独使用,并且与上述一种或多种模式一起使用。

“b”二进制文件模式
     在Windows上抑制EOL < - > CRLF转换。和
     除非明确指定,否则将外部编码设置为ASCII-8BIT
     指定。

“t”文本文件模式

当原始IO的开放模式是只读时,该模式不能改变为可写。同样,开放模式不能从写入变为可读。

当尝试进行这样的改变时,根据平台在不同位置引发错误。

IO 编码

ext_enc指定时,读取的字符串将在读取时由编码标记,并且字符串输出在写入时将转换为指定的编码。

ext_encint_enc被指定时,读取的字符串将从 输入转换ext_encint_enc,写入的字符串将从输出转换int_encext_enc。有关输入和输出转码的更多详细信息,请参阅编码。

如果使用“BOM | UTF-8”,“BOM | UTF-16LE”或“BOM | UTF16-BE”,ruby会检查输入文档中的Unicode BOM以帮助确定编码。对于UTF-16编码,文件打开模式必须是二进制。如果存在,则剥离BOM并使用来自BOM的外部编码。当缺少BOM时,将使用给定的Unicode编码ext_enc。(BOM-set编码选项不区分大小写,所以“bom | utf-8”也是有效的。)

选项

opt可以用来代替mode提高可读性。支持以下密钥:

:模式

mode参数相同

:标志

指定文件打开标志为整数。如果mode给出参数,则此参数将按位或运算。

:external_encoding

IO的外部编码。“ - ”是默认外部编码的同义词。

:internal_encoding

IO的内部编码。“ - ”是默认内部编码的同义词。

如果值为零,则不会发生转换。

:编码

指定外部和内部编码为“extern:intern”。

:文本模式

如果该值是真值,则与参数中的“t”相同mode

:binmode

如果该值是真值,则与参数中的“b”相同mode

:自动关闭

如果该值为false,则fd该IO实例完成后将保持打开状态。

此外,opt在String#编码中可以具有相同的键以控制外部编码和内部编码之间的转换。

Example 1

fd = IO.sysopen("/dev/tty", "w")
a = IO.new(fd,"w")
$stderr.puts "Hello"
a.puts "World"

Produces:

Hello
World

Example 2

require 'fcntl'

fd = STDERR.fcntl(Fcntl::F_DUPFD)
io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
io.puts "Hello, World!"

fd = STDERR.fcntl(Fcntl::F_DUPFD)
io = IO.new(fd, mode: 'w', cr_newline: true,
            external_encoding: Encoding::UTF_16LE)
io.puts "Hello, World!"

以上两种都将UTF-16LE中的“Hello,World!”打印成标准错误输出,并将生成的EOL转换puts为CR。

  static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
    VALUE fnum, vmode;
    rb_io_t *fp;
    int fd, fmode, oflags = O_RDONLY;
    convconfig_t convconfig;
    VALUE opt;
#if defined(HAVE_FCNTL) && defined(F_GETFL)
    int ofmode;
#else
    struct stat st;
#endif


    argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
    rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);

    fd = NUM2INT(fnum);
    if (rb_reserved_fd_p(fd)) {
        rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
    }
#if defined(HAVE_FCNTL) && defined(F_GETFL)
    oflags = fcntl(fd, F_GETFL);
    if (oflags == -1) rb_sys_fail(0);
#else
    if (fstat(fd, &st) == -1) rb_sys_fail(0);
#endif
    rb_update_max_fd(fd);
#if defined(HAVE_FCNTL) && defined(F_GETFL)
    ofmode = rb_io_oflags_fmode(oflags);
    if (NIL_P(vmode)) {
        fmode = ofmode;
    }
    else if ((~ofmode & fmode) & FMODE_READWRITE) {
        VALUE error = INT2FIX(EINVAL);
        rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
    }
#endif
    if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
        fmode |= FMODE_PREP;
    }
    MakeOpenFile(io, fp);
    fp->fd = fd;
    fp->mode = fmode;
    fp->encs = convconfig;
    clear_codeconv(fp);
    io_check_tty(fp);
    if (fileno(stdin) == fd)
        fp->stdio_file = stdin;
    else if (fileno(stdout) == fd)
        fp->stdio_file = stdout;
    else if (fileno(stderr) == fd)
        fp->stdio_file = stderr;

    if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
    return io;
}

open(fd, mode="r" [, opt]) → io

open(fd, mode="r" [, opt]) { |io| block } → obj

没有关联的块,IO.open是:: new的同义词。如果给出了可选的代码块,它将io作为参数传递,当块终止时,IO对象将自动关闭。在这种情况下,::open 返回块的值。

见::new的的描述 fdmodeopt参数。

               static VALUE
rb_io_s_open(int argc, VALUE *argv, VALUE klass)
{
    VALUE io = rb_class_new_instance(argc, argv, klass);

    if (rb_block_given_p()) {
        return rb_ensure(rb_yield, io, io_close, io);
    }

    return io;
}

pipe → [read_io, write_io]

pipe(ext_enc) → [read_io, write_io]

pipe("ext_enc:int_enc" [, opt]) → [read_io, write_io]

pipe(ext_enc, int_enc [, opt]) → [read_io, write_io]

pipe(...) {|read_io, write_io| ... }

创建一对管道端点(相互连接)并将它们作为IO对象的两个元素数组返回:[ read_iowrite_io ]

如果给出一个块,则调用该块并返回该块的值。read_iowrite_io作为参数发送到块。如果在块退出时read_io和write_io未关闭,则它们将关闭。即关闭read_io和/或write_io不会导致错误。

不适用于所有平台。

如果将编码(编码名称或编码对象)指定为可选参数,则从管道读取的字符串将使用指定的编码进行标记。如果参数是以冒号分隔的两个编码名称“A:B”,则读取的字符串从编码A(外部编码)转换为编码B(内部编码),然后用B标记。如果指定了两个可选参数,那么必须是编码对象或编码名称,第一个是外部编码,第二个是内部编码。如果指定了外部编码和内部编码,则可选散列参数指定转换选项。

在下面的示例中,这两个进程关闭了它们未使用的管道末端。这不仅仅是一个化妆品的细节。如果有管道仍然打开的任何写入者,管道的读取结束将不会生成文件结束条件。在父进程的情况下,rd.read如果它不首先发出, 它将永远不会返回 wr.close

rd, wr = IO.pipe

if fork
  wr.close
  puts "Parent got: <#{rd.read}>"
  rd.close
  Process.wait
else
  rd.close
  puts "Sending message to parent"
  wr.write "Hi Dad"
  wr.close
end

生成:

Sending message to parent
Parent got: <Hi Dad>

popen([env,] cmd, mode="r" [, opt]) → io

popen([env,] cmd, mode="r" [, opt]) {|io| block } → obj

将指定的命令作为子进程运行; 子进程的标准输入和输出将连接到返回的IO对象。

启动的进程的PID可以通过#pid方法获得。

cmd是一个字符串或数组,如下所示。

cmd:
  "-"                                      : fork
  commandline                              : command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          : command name and zero or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell)
(env and opts are optional.)

如果cmdString-”,那么Ruby的新实例将作为子进程启动。

如果CMDArrayString,那么它将被用作子过程的argv绕过的壳。该数组首先可以包含一个散列,而对于类似的选项可以包含散列spawn

新文件对象的默认模式是“r”,但模式 可以设置为类IO描述中列出的任何模式。最后一个参数选择合格 模式

# set IO encoding
IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
  euc_jp_string = nkf_io.read
}

# merge standard output and standard error using
# spawn option.  See the document of Kernel.spawn.
IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io|
  ls_result_with_error = ls_io.read
}

# spawn options can be mixed with IO options
IO.popen(["ls", "/"], :err=>[:child, :out]) {|ls_io|
  ls_result_with_error = ls_io.read
}

引发异常IO.pipe并引发异常Kernel.spawn

如果给出了一个块,Ruby将作为一个连接到Ruby的孩子使用管道运行该命令。Ruby的管道末端将作为参数传递给块。在块的最后,Ruby关闭管道并设置 $?。在这种情况下IO.popen返回块的值。

如果一个块的cmd为“ -”,那么该块将在两个独立的进程中运行:一次在父进程中,一次在子进程中。父进程将作为参数传递给管道对象,块的子版本将被传递nil,并且子进程的标准输入和标准输出将通过管道连接到父进程 。不适用于所有平台。

f = IO.popen("uname")
p f.readlines
f.close
puts "Parent is #{Process.pid}"
IO.popen("date") { |f| puts f.gets }
IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
p $?
IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
  f.puts "bar"; f.close_write; puts f.gets
}

生成:

["Linux\n"]
Parent is 21346
Thu Jan 15 22:41:19 JST 2009
21346 is here, f is #<IO:fd 3>
21352 is here, f is nil
#<Process::Status: pid 21352 exit 0>
<foo>bar;zot;

read(name, [length [, offset]] [, opt] ) → string

打开文件,可选择寻找给定的offset,然后返回length字节(默认为文件的其余部分)。read确保文件在返回之前关闭。

选项¶ ↑

选项哈希接受以下键:

编码

字符串或编码

指定读取字符串的编码。 encoding:将被忽略,如果length指定。有关可能的编码,请参阅Encoding.aliases。

模式

指定open()的模式参数。它必须以“r”开头,否则会导致错误。请参阅:新的可用模式列表。

open_args

字符串数组

将open()的参数指定为数组。此密钥不能与任一encoding:或两者结合使用mode:

示例:

IO.read("testfile")              #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
IO.read("testfile", 20)          #=> "This is line one\nThi"
IO.read("testfile", 20, 10)      #=> "ne one\nThis is line "
IO.read("binfile", mode: "rb")   #=> "\xF7\x00\x00\x0E\x12"

readlines(name, sep=$/ [, open_args]) → array

readlines(name, limit [, open_args]) → array

readlines(name, sep, limit [, open_args]) → array

名称指定的整个文件读取为单独的行,并将这些行返回到数组中。行由sep分隔。

a = IO.readlines("testfile")
a[0]   #=> "This is line one\n"

如果最后一个参数是散列,则它是要打开的关键字参数。请参阅IO.read详细信息。

select(read_array [, write_array [, error_array [, timeout]]]) → array or nil

调用选择(2)系统d调用。它监视给定的IO 对象数组,等待一个或多个IO对象准备好读取,准备好写入并分别具有未决异常,并返回一个包含这些IO 对象数组的数组。nil如果给定了可选的超时值并且超时 秒内没有IO对象准备就绪,它将返回。

IO.select偷看IO对象的缓冲区以测试可读性。如果IO缓冲区不是空的, IO.select立即通知可读性。这个“窥视”只发生在IO物体上。它不会发生类似IO的对象,例如OpenSSL :: SSL :: SSLSocket。

用最好的方式IO.select是非阻塞的方法,如后调用它read_nonblockwrite_nonblock等。该方法提高其通过扩展一个异常 IO::WaitReadableIO::WaitWritable。模块通知呼叫方应该如何等待IO.select。如果 IO::WaitReadable提出,主叫方应该等待阅读。如果IO::WaitWritable被提出,则调用者应该等待写入。

所以,readpartial可以使用read_nonblock和模拟阻塞read() IO.select,如下所示:

begin
  result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io_like])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io_like])
  retry
end

尤其是,非阻塞方法的组合,并且 IO.select对于IO类似的对象比较喜欢OpenSSL::SSL::SSLSocket。它有to_io返回基础IO对象的方法。IO.select调用 to_io获取文件描述符以等待。

这意味着通知的IO.select可读性并不意味着可读性OpenSSL::SSL::SSLSocket

最可能的情况是OpenSSL::SSL::SSLSocket 缓冲一些数据。IO.select没有看到缓冲区。所以IO.select可以阻挡何时 OpenSSL::SSL::SSLSocket#readpartial不阻挡。

然而,存在几个更复杂的情况。

SSL是一个记录序列的协议。该记录由多个字节组成。所以,SSL的远程端发送一个部分记录, IO.select通知可读性但 OpenSSL::SSL::SSLSocket不能解密一个字节,并OpenSSL::SSL::SSLSocket#readpartial会阻塞。

另外,远程端可以请求SSL重新协商,强制本地SSL引擎写入一些数据。这意味着OpenSSL::SSL::SSLSocket#readpartial可能会调用 write系统调用,并且可能会阻塞。在这种情况下, OpenSSL::SSL::SSLSocket#read_nonblock引发IO :: WaitWritable而不是阻塞。因此,调用者应该等待上述例子的可写性。

非阻塞方法的组合,IO.select当流从多个流中读取时,对于诸如tty,管道套接字套接字等流也很有用。

最后,Linux内核开发人员不保证select(2)的可读性意味着即使对于单个进程也可以读取(2)。请参阅GNU / Linux系统上的选择(2)手册。

IO.selectIO#readpartial平常工作之前调用。但它不是最好的使用方法 IO.select

select(2)通知的可写性不显示可写入​​多少字节。IO#write方法阻塞,直到写入完整的字符串。所以,IO#write(two or more bytes)可写性通知后可以阻塞IO.selectIO#write_nonblock需要避免阻塞。

阻塞写(write)可以使用模拟 write_nonblockIO.select如下:IO :: WaitReadable也应该救在SSL重新协商OpenSSL::SSL::SSLSocket

while 0 < string.bytesize
  begin
    written = io_like.write_nonblock(string)
  rescue IO::WaitReadable
    IO.select([io_like])
    retry
  rescue IO::WaitWritable
    IO.select(nil, [io_like])
    retry
  end
  string = string.byteslice(written..-1)
end

参数¶ ↑

read_array

IO等待准备读取的对象数组

write_array

IO等待准备写入的对象数组

error_array

IO等待异常的对象数组

时间到

以秒为单位的数值

示例:

rp, wp = IO.pipe
mesg = "ping "
100.times {
  # IO.select follows IO#read.  Not the best way to use IO.select.
  rs, ws, = IO.select([rp], [wp])
  if r = rs[0]
    ret = r.read(5)
    print ret
    case ret
    when /ping/
      mesg = "pong\n"
    when /pong/
      mesg = "ping "
    end
  end
  if w = ws[0]
    w.write(mesg)
  end
}

产出:

ping pong
ping pong
ping pong
(snipped)
ping
               static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
    VALUE timeout;
    struct select_args args;
    struct timeval timerec;
    int i;

    rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
    if (NIL_P(timeout)) {
        args.timeout = 0;
    }
    else {
        timerec = rb_time_interval(timeout);
        args.timeout = &timerec;
    }

    for (i = 0; i < numberof(args.fdsets); ++i)
        rb_fd_init(&args.fdsets[i]);

    return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
}

sysopen(path, [mode, [perm]]) → fixnum

打开给定路径,将基础文件描述符返回为Fixnum

IO.sysopen("testfile")   #=> 3

try_convert(obj) → io or nil

尝试使用#to_io方法将obj转换为IO。如果因任何原因无法转换obj,则返回已转换的IO或零。

IO.try_convert(STDOUT)     #=> STDOUT
IO.try_convert("STDOUT")   #=> nil

require 'zlib'
f = open("/tmp/zz.gz")       #=> #<File:/tmp/zz.gz>
z = Zlib::GzipReader.open(f) #=> #<Zlib::GzipReader:0x81d8744>
IO.try_convert(z)            #=> #<File:/tmp/zz.gz>

write(name, string, [offset] ) => fixnum

write(name, string, [offset], open_args ) => fixnum

打开文件,可选择查找给定的偏移量,写入 字符串,然后返回写入的长度。write 确保文件在返回之前关闭。如果没有给出偏移量,则文件被截断。否则,它不会被截断。

如果最后一个参数是一个散列,它指定了内部open()的选项。关键是以下几点。open_args:是别人专用的。

encoding: string or encoding

 specifies encoding of the read string.  encoding will be ignored
 if length is specified.

mode: string

 specifies mode argument for open().  it should start with "w" or "a" or "r+"
 otherwise it would cause error.

perm: fixnum

 specifies perm argument for open().

open_args: array

 specifies arguments for open() as an array.

  IO.write("testfile", "0123456789", 20) # => 10
  # File could contain:  "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
  IO.write("testfile", "0123456789")      #=> 10
  # File would now read: "0123456789"

公共实例方法

ios << obj→ios

字符串输出,写入OBJIOSobj将被转换为一个字符串使用 to_s

$ stdout  <<  “Hello”  <<  “world!\ n”

生产:

Hello world!

advise(advice, offset=0, len=0) → nil

宣布打算以特定模式访问当前文件中的数据。在不支持posix_fadvise(2) 系统调用的平台上,此方法是无操作的。

建议是以下符号之一:

:normal

没有建议给; 打开文件的默认假设。

:sequential

数据将按顺序访问,在较高偏移之前读取较低的偏移量。

:random

数据将以随机顺序访问。

:willneed

数据将在不久的将来被访问。

:dontneed

这些数据在不久的将来将不会被访问。

:noreuse

数据只会被访问一次。

一条建议的语义与平台有关。详情请参阅man 2 posix_fadvise

“数据”表示当前文件的区域,该区域以偏移量开始 并扩展为len字节。如果len为0,则该区域结束于文件的最后一个字节。默认情况下,offsetlen都是0,这意味着该建议适用于整个文件。

如果发生错误,则会引发以下异常之一:

IOError

IO流已关闭。

Errno::EBADF

当前文件的文件描述符无效。

Errno::EINVAL

给出了一个无效的建议价值。

Errno::ESPIPE

当前文件的文件描述符指的是FIFO或管道。(Linux Errno::EINVAL在这种情况下引发)。

TypeError

要么建议不是一个符号,或者其他的一个参数不是一个Integer

RangeError

其中一个观点太大/太小。

这份清单并非详尽无遗;其他Errno

例外也是可能的。

autoclose = bool→true或false

设置自动关闭标志。

f = open("/dev/null")
IO.for_fd(f.fileno)
# ...
f.gets # may cause IOError

f = open("/dev/null")
IO.for_fd(f.fileno).autoclose = true
# ...
f.gets # won't cause IOError
               static VALUE
rb_io_set_autoclose(VALUE io, VALUE autoclose)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (!RTEST(autoclose))
        fptr->mode |= FMODE_PREP;
    else
        fptr->mode &= ~FMODE_PREP;
    return io;
}

autoclose? → true or false

返回iostrue的基础文件描述符是否会在其终止时自动关闭,否则返回false

               static VALUE
rb_io_autoclose_p(VALUE io)
{
    rb_io_t *fptr = RFILE(io)->fptr;
    rb_io_check_closed(fptr);
    return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
}

binmode → ios

ios置于二进制模式。一旦流处于二进制模式,它不能被重置为非二进制模式。

  • 新行转换已禁用
  • 编码转换禁用
  • 内容被视为ASCII-8BIT
static VALUE
rb_io_binmode_m(VALUE io)
{
    VALUE write_io;

    rb_io_ascii8bit_binmode(io);

    write_io = GetWriteIO(io);
    if (write_io != io)
        rb_io_ascii8bit_binmode(write_io);
    return io;
}

binmode? → true or false

如果ios是binmode,则返回true

static VALUE
rb_io_binmode_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
}

bytes()

这是一个不推荐的别名each_byte

static VALUE
rb_io_bytes(VALUE io)
{
    rb_warn("IO#bytes is deprecated; use #each_byte instead");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
    return rb_io_each_byte(io);
}

chars()

这是一个不推荐的别名each_char

static VALUE
rb_io_chars(VALUE io)
{
    rb_warn("IO#chars is deprecated; use #each_char instead");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
    return rb_io_each_char(io);
}

close → nil

关闭ios并刷新任何挂起的写入操作系统。该流不可用于任何进一步的数据操作; 一IOError,如果这样的尝试升高。I/O流在被垃圾回收器声明时会自动关闭。

如果ios被打开IO.popenclose设置$?

从Ruby 2.3开始,在封闭的IO对象上调用这个方法就被忽略了。

static VALUE
rb_io_close_m(VALUE io)
{
    rb_io_t *fptr = rb_io_get_fptr(io);
    if (fptr->fd < 0) {
        return Qnil;
    }
    rb_io_close(io);
    return Qnil;
}

close_on_exec = bool → true or false

设置一个关闭执行标志。

f = open("/dev/null")
f.close_on_exec = true
system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
f.closed?                #=> false

从Ruby 2.0.0开始,Ruby默认设置所有文件描述符的close-on-exec标志。所以你不需要自己设定。另外,如果另一个线程使用fork()和exec()(例如通过system()方法),则取消设置close-on-exec标志可能导致文件描述符泄漏。如果您真的需要将文件描述符继承到子进程,请使用spawn()的参数,如fd => fd。

static VALUE
rb_io_set_close_on_exec(VALUE io, VALUE arg)
{
    int flag = RTEST(arg) ? FD_CLOEXEC : 0;
    rb_io_t *fptr;
    VALUE write_io;
    int fd, ret;

    write_io = GetWriteIO(io);
    if (io != write_io) {
        GetOpenFile(write_io, fptr);
        if (fptr && 0 <= (fd = fptr->fd)) {
            if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
            if ((ret & FD_CLOEXEC) != flag) {
                ret = (ret & ~FD_CLOEXEC) | flag;
                ret = fcntl(fd, F_SETFD, ret);
                if (ret == -1) rb_sys_fail_path(fptr->pathv);
            }
        }

    }

    GetOpenFile(io, fptr);
    if (fptr && 0 <= (fd = fptr->fd)) {
        if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
        if ((ret & FD_CLOEXEC) != flag) {
            ret = (ret & ~FD_CLOEXEC) | flag;
            ret = fcntl(fd, F_SETFD, ret);
            if (ret == -1) rb_sys_fail_path(fptr->pathv);
        }
    }
    return Qnil;
}

close_on_exec? → true or false

如果ios将在exec上关闭,则返回true

f = open("/dev/null")
f.close_on_exec?                 #=> false
f.close_on_exec = true
f.close_on_exec?                 #=> true
f.close_on_exec = false
f.close_on_exec?                 #=> false
static VALUE
rb_io_close_on_exec_p(VALUE io)
{
    rb_io_t *fptr;
    VALUE write_io;
    int fd, ret;

    write_io = GetWriteIO(io);
    if (io != write_io) {
        GetOpenFile(write_io, fptr);
        if (fptr && 0 <= (fd = fptr->fd)) {
            if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
            if (!(ret & FD_CLOEXEC)) return Qfalse;
        }
    }

    GetOpenFile(io, fptr);
    if (fptr && 0 <= (fd = fptr->fd)) {
        if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
        if (!(ret & FD_CLOEXEC)) return Qfalse;
    }
    return Qtrue;
}

close_read → nil Show source

关闭duplex I/O流的读取端(即,包含读取和写入流的管道,例如管道)。IOError如果数据流不是双工的,会引发一次。

f = IO.popen("/bin/sh","r+")
f.close_read
f.readlines

produces:

prog.rb:3:in `readlines': not opened for reading (IOError)
 from prog.rb:3
static VALUE
rb_io_close_read(VALUE io)
{
    rb_io_t *fptr;
    VALUE write_io;

    fptr = rb_io_get_fptr(rb_io_taint_check(io));
    if (fptr->fd < 0) return Qnil;
    if (is_socket(fptr->fd, fptr->pathv)) {
#ifndef SHUT_RD
# define SHUT_RD 0
#endif
        if (shutdown(fptr->fd, SHUT_RD) < 0)
            rb_sys_fail_path(fptr->pathv);
        fptr->mode &= ~FMODE_READABLE;
        if (!(fptr->mode & FMODE_WRITABLE))
            return rb_io_close(io);
        return Qnil;
    }

    write_io = GetWriteIO(io);
    if (io != write_io) {
        rb_io_t *wfptr;
        wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
        wfptr->pid = fptr->pid;
        fptr->pid = 0;
        RFILE(io)->fptr = wfptr;
        /* bind to write_io temporarily to get rid of memory/fd leak */
        fptr->tied_io_for_writing = 0;
        RFILE(write_io)->fptr = fptr;
        rb_io_fptr_cleanup(fptr, FALSE);
        /* should not finalize fptr because another thread may be reading it */
        return Qnil;
    }

    if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
        rb_raise(rb_eIOError, "closing non-duplex IO for reading");
    }
    return rb_io_close(io);
}

close_write → nil Show source

关闭duplex I/O流的写入结束(即,包含读取和写入流的管道,例如管道)。IOError如果数据流不是双工的,会引发一次。

f = IO.popen("/bin/sh","r+")
f.close_write
f.print "nowhere"

produces:

prog.rb:3:in `write': not opened for writing (IOError)
 from prog.rb:3:in `print'
 from prog.rb:3
static VALUE
rb_io_close_write(VALUE io)
{
    rb_io_t *fptr;
    VALUE write_io;

    write_io = GetWriteIO(io);
    fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
    if (fptr->fd < 0) return Qnil;
    if (is_socket(fptr->fd, fptr->pathv)) {
#ifndef SHUT_WR
# define SHUT_WR 1
#endif
        if (shutdown(fptr->fd, SHUT_WR) < 0)
            rb_sys_fail_path(fptr->pathv);
        fptr->mode &= ~FMODE_WRITABLE;
        if (!(fptr->mode & FMODE_READABLE))
            return rb_io_close(write_io);
        return Qnil;
    }

    if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
        rb_raise(rb_eIOError, "closing non-duplex IO for writing");
    }

    if (io != write_io) {
        fptr = rb_io_get_fptr(rb_io_taint_check(io));
        fptr->tied_io_for_writing = 0;
    }
    rb_io_close(write_io);
    return Qnil;
}

closed? → true or false Show source

如果ios完全关闭(对于双向流,读写器),则返回true,否则返回false

f = File.new("testfile")
f.close         #=> nil
f.closed?       #=> true
f = IO.popen("/bin/sh","r+")
f.close_write   #=> nil
f.closed?       #=> false
f.close_read    #=> nil
f.closed?       #=> true
static VALUE
rb_io_closed(VALUE io)
{
    rb_io_t *fptr;
    VALUE write_io;
    rb_io_t *write_fptr;

    write_io = GetWriteIO(io);
    if (io != write_io) {
        write_fptr = RFILE(write_io)->fptr;
        if (write_fptr && 0 <= write_fptr->fd) {
            return Qfalse;
        }
    }

    fptr = rb_io_get_fptr(io);
    return 0 <= fptr->fd ? Qfalse : Qtrue;
}

codepoints()

这是一个不推荐的别名each_codepoint

static VALUE
rb_io_codepoints(VALUE io)
{
    rb_warn("IO#codepoints is deprecated; use #each_codepoint instead");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0);
    return rb_io_each_codepoint(io);
}

cooked {|io| }

selfcooked模式下的产量。

STDIN.cooked(&:gets)

将读取并返回一行回显和行编辑。

您必须要求'io/console'才能使用此方法。

static VALUE
console_cooked(VALUE io)
{
    return ttymode(io, rb_yield, set_cookedmode, NULL);
}

cooked!

启用cooked模式。

如果终端模式需要返回,请使用io.cooked {...}。

您必须要求'io/console'才能使用此方法。

static VALUE
console_set_cooked(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    set_cookedmode(&t, NULL);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

cursor()

static VALUE
console_cursor_pos(VALUE io)
{
    rb_io_t *fptr;
    int fd;
    rb_console_size_t ws;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.X), UINT2NUM(ws.dwCursorPosition.Y));
}

cursor=(p1)

static VALUE
console_cursor_set(VALUE io, VALUE cpos)
{
    cpos = rb_convert_type(cpos, T_ARRAY, "Array", "to_ary");
    if (RARRAY_LEN(cpos) != 2) rb_raise(rb_eArgError, "expected 2D coordinate");
    return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
}

each(sep=$/) {|line| block } → ios

each(limit) {|line| block } → ios

each(sep,limit) {|line| block } → ios

each(...) → an_enumerator

each_line(sep=$/) {|line| block } → ios

each_line(limit) {|line| block } → ios

each_line(sep,limit) {|line| block } → ios

each_line(...) → an_enumerator

ios中的每一行执行块,其中行由sep分隔。ios必须打开以供阅读或IOError将会被提出。

如果没有给出块,则返回一个枚举器。

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }

produces:

1: This is line one
2: This is line two
3: This is line three
4: And so on...
static VALUE
rb_io_each_line(int argc, VALUE *argv, VALUE io)
{
    VALUE str;
    struct getline_arg args;

    RETURN_ENUMERATOR(io, argc, argv);
    prepare_getline_args(argc, argv, &args, io);
    if (args.limit == 0)
        rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
    while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
        rb_yield(str);
    }
    return io;
}

each_byte {|byte| block } → ios Show source

each_byte → an_enumerator

ios中的每个字节(0..255)调用给定的块一次,将该字节作为参数传递。该流必须打开阅读或IOError将被提出。

如果没有给出块,则返回一个枚举器。

f = File.new("testfile")
checksum = 0
f.each_byte {|x| checksum ^= x }   #=> #<File:testfile>
checksum                           #=> 12
static VALUE
rb_io_each_byte(VALUE io)
{
    rb_io_t *fptr;

    RETURN_ENUMERATOR(io, 0, 0);
    GetOpenFile(io, fptr);

    do {
        while (fptr->rbuf.len > 0) {
            char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
            fptr->rbuf.len--;
            rb_yield(INT2FIX(*p & 0xff));
            errno = 0;
        }
        rb_io_check_byte_readable(fptr);
        READ_CHECK(fptr);
    } while (io_fillbuf(fptr) >= 0);
    return io;
}

each_char {|c| block } → ios Show source

each_char → an_enumerator

ios中的每个字符调用一次给定的块,将该字符作为参数传递。该流必须打开阅读或IOError将被提出。

如果没有给出块,则返回一个枚举器。

f = File.new("testfile")
f.each_char {|c| print c, ' ' }   #=> #<File:testfile>
static VALUE
rb_io_each_char(VALUE io)
{
    rb_io_t *fptr;
    rb_encoding *enc;
    VALUE c;

    RETURN_ENUMERATOR(io, 0, 0);
    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);

    enc = io_input_encoding(fptr);
    READ_CHECK(fptr);
    while (!NIL_P(c = io_getc(fptr, enc))) {
        rb_yield(c);
    }
    return io;
}

each_codepoint {|c| block } → ios Show source

codepoints {|c| block } → ios

each_codepoint → an_enumerator

codepoints → an_enumerator

传递iosInteger中每个字符的序号,将代码点作为参数传递。该流必须打开阅读或将被提出。IOError

如果没有给出块,则返回一个枚举器。

static VALUE
rb_io_each_codepoint(VALUE io)
{
    rb_io_t *fptr;
    rb_encoding *enc;
    unsigned int c;
    int r, n;

    RETURN_ENUMERATOR(io, 0, 0);
    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);

    READ_CHECK(fptr);
    if (NEED_READCONV(fptr)) {
        SET_BINARY_MODE(fptr);
        r = 1;         /* no invalid char yet */
        for (;;) {
            make_readconv(fptr, 0);
            for (;;) {
                if (fptr->cbuf.len) {
                    if (fptr->encs.enc)
                        r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
                                                  fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
                                                  fptr->encs.enc);
                    else
                        r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
                    if (!MBCLEN_NEEDMORE_P(r))
                        break;
                    if (fptr->cbuf.len == fptr->cbuf.capa) {
                        rb_raise(rb_eIOError, "too long character");
                    }
                }
                if (more_char(fptr) == MORE_CHAR_FINISHED) {
                    clear_readconv(fptr);
                    if (!MBCLEN_CHARFOUND_P(r)) {
                        enc = fptr->encs.enc;
                        goto invalid;
                    }
                    return io;
                }
            }
            if (MBCLEN_INVALID_P(r)) {
                enc = fptr->encs.enc;
                goto invalid;
            }
            n = MBCLEN_CHARFOUND_LEN(r);
            if (fptr->encs.enc) {
                c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
                                     fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
                                     fptr->encs.enc);
            }
            else {
                c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
            }
            fptr->cbuf.off += n;
            fptr->cbuf.len -= n;
            rb_yield(UINT2NUM(c));
        }
    }
    NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
    enc = io_input_encoding(fptr);
    while (io_fillbuf(fptr) >= 0) {
        r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
                                  fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
        if (MBCLEN_CHARFOUND_P(r) &&
            (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
            c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
                                 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
            fptr->rbuf.off += n;
            fptr->rbuf.len -= n;
            rb_yield(UINT2NUM(c));
        }
        else if (MBCLEN_INVALID_P(r)) {
          invalid:
            rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
        }
        else if (MBCLEN_NEEDMORE_P(r)) {
            char cbuf[8], *p = cbuf;
            int more = MBCLEN_NEEDMORE_LEN(r);
            if (more > numberof(cbuf)) goto invalid;
            more += n = fptr->rbuf.len;
            if (more > numberof(cbuf)) goto invalid;
            while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
                   (p += n, (more -= n) > 0)) {
                if (io_fillbuf(fptr) < 0) goto invalid;
                if ((n = fptr->rbuf.len) > more) n = more;
            }
            r = rb_enc_precise_mbclen(cbuf, p, enc);
            if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
            c = rb_enc_codepoint(cbuf, p, enc);
            rb_yield(UINT2NUM(c));
        }
        else {
            continue;
        }
    }
    return io;
}

each_line(sep=$/) {|line| block } → ios

each_line(limit) {|line| block } → ios

each_line(sep,limit) {|line| block } → ios

each_line(...) → an_enumerator

ios中的每一行执行块,其中行由sep分隔。ios必须打开以供阅读或IOError将会被提出。

如果没有给出块,则返回一个枚举器。

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }

produces:

1: This is line one
2: This is line two
3: This is line three
4: And so on...
static VALUE
rb_io_each_line(int argc, VALUE *argv, VALUE io)
{
    VALUE str;
    struct getline_arg args;

    RETURN_ENUMERATOR(io, argc, argv);
    prepare_getline_args(argc, argv, &args, io);
    if (args.limit == 0)
        rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
    while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
        rb_yield(str);
    }
    return io;
}

echo = flag Show source

启用/禁用回显。在某些平台上,此标志和原始/熟化模式的所有组合可能无效。

您必须要求'io / console'才能使用此方法。

static VALUE
console_set_echo(VALUE io, VALUE f)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    if (RTEST(f))
        set_echo(&t, NULL);
    else
        set_noecho(&t, NULL);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

echo? → true or false Show source

如果启用了回显,则返回true

您必须要求'io/console'才能使用此方法。

static VALUE
console_echo_p(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    return echo_p(&t) ? Qtrue : Qfalse;
}

eof → true or false

eof? → true or false

如果ios在文件末尾,表示没有更多数据要读取,则返回true 。该流必须打开阅读或IOError将被提出。

f = File.new("testfile")
dummy = f.readlines
f.eof   #=> true

如果ios是诸如管道或套接字之类的流,则IO#eof?阻塞直到另一端发送一些数据或关闭它。

r, w = IO.pipe
Thread.new { sleep 1; w.close }
r.eof?  #=> true after 1 second blocking

r, w = IO.pipe
Thread.new { sleep 1; w.puts "a" }
r.eof?  #=> false after 1 second blocking

r, w = IO.pipe
r.eof?  # blocks forever

请注意,IO#eof?将数据读取到输入字节缓冲区。因此,除非您先调用(不适用于某些流),否则IO#sysread可能无法按照您的意愿行事。IO#eof?IO#rewind

VALUE
rb_io_eof(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);

    if (READ_CHAR_PENDING(fptr)) return Qfalse;
    if (READ_DATA_PENDING(fptr)) return Qfalse;
    READ_CHECK(fptr);
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
        return eof(fptr->fd) ? Qtrue : Qfalse;
    }
#endif
    if (io_fillbuf(fptr) < 0) {
        return Qtrue;
    }
    return Qfalse;
}

eof? → true or false

如果ios在文件末尾,表示没有更多数据要读取,则返回true 。该流必须打开阅读或IOError将被提出。

f = File.new("testfile")
dummy = f.readlines
f.eof   #=> true

如果ios是诸如管道或套接字之类的流,则IO#eof?阻塞直到另一端发送一些数据或关闭。

r, w = IO.pipe
Thread.new { sleep 1; w.close }
r.eof?  #=> true after 1 second blocking

r, w = IO.pipe
Thread.new { sleep 1; w.puts "a" }
r.eof?  #=> false after 1 second blocking

r, w = IO.pipe
r.eof?  # blocks forever

请注意,IO#eof?将数据读取到输入字节缓冲区。因此,除非您先调用IO#rewind(不适用于某些流),否则IO#sysread可能无法按照您IO#eof?的意愿行事。

VALUE
rb_io_eof(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);

    if (READ_CHAR_PENDING(fptr)) return Qfalse;
    if (READ_DATA_PENDING(fptr)) return Qfalse;
    READ_CHECK(fptr);
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
        return eof(fptr->fd) ? Qtrue : Qfalse;
    }
#endif
    if (io_fillbuf(fptr) < 0) {
        return Qtrue;
    }
    return Qfalse;
}

IO#expect(pattern,timeout=9999999) → Array

IO#expect(pattern,timeout=9999999) { |result| ... } → nil

从IO中读取,直到给定的pattern匹配或timeout结束。

它返回一个带有读缓冲区的数组,然后是匹配。如果给出了一个块,结果将被输出到该块并返回nil。

在没有块的情况下调用时,它会一直等待,直到pattern从IO获得匹配给定的输入或者超时过后指定的时间。从IO获取模式时返回数组。数组的第一个元素是从IO中获得的整个字符串,直到模式匹配,然后是指示哪些模式与正则表达式中的锚点匹配的元素。

可选的超时参数以秒为单位定义等待模式的总时间。如果超时到期或找到eof,返回或放弃nil。但是,超时会话中的缓冲区将保留用于下一个期望调用。默认超时时间为9999999秒。

# File ext/pty/lib/expect.rb, line 32
def expect(pat,timeout=9999999)
  buf = ''
  case pat
  when String
    e_pat = Regexp.new(Regexp.quote(pat))
  when Regexp
    e_pat = pat
  else
    raise TypeError, "unsupported pattern class: #{pat.class}"
  end
  @unusedBuf ||= ''
  while true
    if not @unusedBuf.empty?
      c = @unusedBuf.slice!(0).chr
    elsif !IO.select([self],nil,nil,timeout) or eof? then
      result = nil
      @unusedBuf = buf
      break
    else
      c = getc.chr
    end
    buf << c
    if $expect_verbose
      STDOUT.print c
      STDOUT.flush
    end
    if mat=e_pat.match(buf) then
      result = [buf,*mat.to_a[1..-1]]
      break
    end
  end
  if block_given? then
    yield result
  else
    return result
  end
  nil
end

external_encoding → encoding

返回表示文件编码的Encoding对象。如果io是写入模式并且没有指定编码,则返回nil

static VALUE
rb_io_external_encoding(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (fptr->encs.enc2) {
        return rb_enc_from_encoding(fptr->encs.enc2);
    }
    if (fptr->mode & FMODE_WRITABLE) {
        if (fptr->encs.enc)
            return rb_enc_from_encoding(fptr->encs.enc);
        return Qnil;
    }
    return rb_enc_from_encoding(io_read_encoding(fptr));
}

fcntl(integer_cmd, arg) → integer Show source

提供一种发布低级命令来控制或​​查询面向文件的I/O流的机制。参数和结果依赖于平台。如果arg是数字,则其值直接传递。如果它是一个字符串,则将其解释为二进制字节序列(Array#pack可能是构建此字符串的一种有用方法)。在Unix平台上,查看fcntl(2)详情。没有在所有平台上实施。

static VALUE
rb_io_fcntl(int argc, VALUE *argv, VALUE io)
{
    VALUE req, arg;

    rb_scan_args(argc, argv, "11", &req, &arg);
    return rb_fcntl(io, req, arg);
}

fdatasync → 0 or nil

在立即写入所有缓冲数据的ios到磁盘。

如果底层操作系统不支持fdatasync(2)IO#fsync则会调用(可能会引发NotImplementedError)。

static VALUE
rb_io_fdatasync(VALUE io)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);

    if (io_fflush(fptr) < 0)
        rb_sys_fail(0);

    if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
        return INT2FIX(0);

    /* fall back */
    return rb_io_fsync(io);
}

fileno → integer

to_i → integer

返回表示ios的数字文件描述符的整数。

$stdin.fileno    #=> 0
$stdout.fileno   #=> 1
static VALUE
rb_io_fileno(VALUE io)
{
    rb_io_t *fptr = RFILE(io)->fptr;
    int fd;

    rb_io_check_closed(fptr);
    fd = fptr->fd;
    return INT2FIX(fd);
}

另外别名为:to_i

flush → ios

ios中的任何缓冲数据刷新到底层操作系统(请注意,这仅仅是Ruby内部缓冲;操作系统也可以缓冲数据)。

$stdout.print "no newline"
$stdout.flush

produces:

no newline
VALUE
rb_io_flush(VALUE io)
{
    return rb_io_flush_raw(io, 1);
}

fsync → 0 or nil

在立即写入所有缓冲数据的ios到磁盘。请注意,fsync与使用不同IO#sync=。后者确保数据从Ruby的缓冲区刷新,但不保证底层操作系统实际将其写入磁盘。

NotImplementedError如果底层操作系统不支持fsync(2),则会引发此问题。

static VALUE
rb_io_fsync(VALUE io)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);

    if (io_fflush(fptr) < 0)
        rb_sys_fail(0);
    if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
        rb_sys_fail_path(fptr->pathv);
    return INT2FIX(0);
}

getbyte → integer or nil

ios获取下一个8位字节(0..255)。nil如果在文件结尾处调用则返回。

f = File.new("testfile")
f.getbyte   #=> 84
f.getbyte   #=> 104
VALUE
rb_io_getbyte(VALUE io)
{
    rb_io_t *fptr;
    int c;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    READ_CHECK(fptr);
    if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(rb_stdout, T_FILE)) {
        rb_io_t *ofp;
        GetOpenFile(rb_stdout, ofp);
        if (ofp->mode & FMODE_TTY) {
            rb_io_flush(rb_stdout);
        }
    }
    if (io_fillbuf(fptr) < 0) {
        return Qnil;
    }
    fptr->rbuf.off++;
    fptr->rbuf.len--;
    c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
    return INT2FIX(c & 0xff);
}

getc → string or nil

ios读取一个字符的字符串。nil如果在文件结尾处调用则返回。

f = File.new("testfile")
f.getc   #=> "h"
f.getc   #=> "e"
static VALUE
rb_io_getc(VALUE io)
{
    rb_io_t *fptr;
    rb_encoding *enc;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);

    enc = io_input_encoding(fptr);
    READ_CHECK(fptr);
    return io_getc(fptr, enc);
}

getch(min: nil, time: nil) → char

读取并返回原始模式下的字符。

您必须要求'io/console'才能使用此方法。

static VALUE
console_getch(int argc, VALUE *argv, VALUE io)
{
    rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);
    return ttymode(io, getc_call, set_rawmode, optp);
}

getpass(prompt=nil) → string

读取并返回没有回显的行。prompt除非是,否则打印nil

您必须要求'io/console'才能使用此方法。

static VALUE
console_getpass(int argc, VALUE *argv, VALUE io)
{
    VALUE str, wio;

    rb_check_arity(argc, 0, 1);
    wio = rb_io_get_write_io(io);
    if (wio == io && io == rb_stdin) wio = rb_stderr;
    prompt(argc, argv, wio);
    str = rb_ensure(getpass_call, io, puts_call, wio);
    return str_chomp(str);
}

gets(sep=$/) → string or nil

gets(limit) → string or nil

gets(sep, limit) → string or nil

从I / O流中读取下一个“line”; 行由sep分隔。一个nil读取整个内容的分隔符,一个零长度分隔符一次读取一个段落的输入(输入单独段落中的两个连续换行符)。该流必须打开阅读或IOError将被提出。读入的行将被返回并分配给$_nil如果在文件结尾处调用则返回。如果第一个参数是一个整数,或者给出了可选的第二个参数,则返回的字符串不会超过以字节为单位的给定值。

File.new("testfile").gets   #=> "This is line one\n"
$_                          #=> "This is line one\n"

File.new("testfile").gets(4)#=> "This"

如果IO包含多字节字符,则字节gets(1)将完全返回字符:

# Russian characters take 2 bytes
File.write("testfile", "\u{442 435 441 442}")
File.open("testfile") {|f|f.gets(1)} #=> "\u0442"
File.open("testfile") {|f|f.gets(2)} #=> "\u0442"
File.open("testfile") {|f|f.gets(3)} #=> "\u0442\u0435"
File.open("testfile") {|f|f.gets(4)} #=> "\u0442\u0435"
static VALUE
rb_io_gets_m(int argc, VALUE *argv, VALUE io)
{
    VALUE str;

    str = rb_io_getline(argc, argv, io);
    rb_lastline_set(str);

    return str;
}

goto(p1, p2)

static VALUE
console_goto(VALUE io, VALUE x, VALUE y)
{
    rb_io_t *fptr;
    int fd;
    COORD pos;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    pos.X = NUM2UINT(x);
    pos.Y = NUM2UINT(y);
    if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    return io;
}

iflush

在内核中刷新输入缓冲区。

您必须要求'io/console'才能使用此方法。

static VALUE
console_iflush(VALUE io)
{
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    if (tcflush(fd, TCIFLUSH)) rb_sys_fail(0);
#endif
    (void)fd;
    return io;
}

inspect → string

返回描述此IO对象的字符串。

static VALUE
rb_io_inspect(VALUE obj)
{
    rb_io_t *fptr;
    VALUE result;
    static const char closed[] = " (closed)";

    fptr = RFILE(obj)->fptr;
    if (!fptr) return rb_any_to_s(obj);
    result = rb_str_new_cstr("#<");
    rb_str_append(result, rb_class_name(CLASS_OF(obj)));
    rb_str_cat2(result, ":");
    if (NIL_P(fptr->pathv)) {
        if (fptr->fd < 0) {
            rb_str_cat(result, closed+1, strlen(closed)-1);
        }
        else {
            rb_str_catf(result, "fd %d", fptr->fd);
        }
    }
    else {
        rb_str_append(result, fptr->pathv);
        if (fptr->fd < 0) {
            rb_str_cat(result, closed, strlen(closed));
        }
    }
    return rb_str_cat2(result, ">");
}

internal_encoding → encoding

如果指定了转换,则返回内部字符串的编码。否则返回零。

static VALUE
rb_io_internal_encoding(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (!fptr->encs.enc2) return Qnil;
    return rb_enc_from_encoding(io_read_encoding(fptr));
}

ioctl(integer_cmd, arg) → integer

提供一种发布低级命令来控制或​​查询I/O设备的机制。参数和结果依赖于平台。如果arg是数字,则其值直接传递。如果它是一个字符串,它将被解释为一个二进制字节序列。在Unix平台上,查看ioctl(2)详情。没有在所有平台上实施。

static VALUE
rb_io_ioctl(int argc, VALUE *argv, VALUE io)
{
    VALUE req, arg;

    rb_scan_args(argc, argv, "11", &req, &arg);
    return rb_ioctl(io, req, arg);
}

ioflush

刷新内核中的输入和输出缓冲区。

您必须要求'io/console'才能使用此方法。

static VALUE
console_ioflush(VALUE io)
{
    rb_io_t *fptr;
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    int fd1, fd2;
#endif

    GetOpenFile(io, fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    fd1 = GetReadFD(fptr);
    fd2 = GetWriteFD(fptr);
    if (fd2 != -1 && fd1 != fd2) {
        if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0);
        if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0);
    }
    else {
        if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0);
    }
#endif
    return io;
}

isatty → true or false

如果ios与终端设备(tty)关联则返回,false否则返回true

File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true
static VALUE
rb_io_isatty(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (isatty(fptr->fd) == 0)
        return Qfalse;
    return Qtrue;
}

lineno → integer

返回ios中的当前行号。该流必须打开才能阅读。lineno统计被调用的次数,而不是所遇到的换行符的数量。如果使用换行符以外的分隔符调用get,则这两个值将有所不同。

像每个$/,行和readline一样使用的方法也会增加lineno

另请参阅$.变量。

f = File.new("testfile")
f.lineno   #=> 0
f.gets     #=> "This is line one\n"
f.lineno   #=> 1
f.gets     #=> "This is line two\n"
f.lineno   #=> 2
static VALUE
rb_io_lineno(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    return INT2NUM(fptr->lineno);
}

lineno = integer → integer

手动将当前行号设置为给定值。$.仅在下次阅读时更新。

f = File.new("testfile")
f.gets                     #=> "This is line one\n"
$.                         #=> 1
f.lineno = 1000
f.lineno                   #=> 1000
$.                         #=> 1         # lineno of last read
f.gets                     #=> "This is line two\n"
$.                         #=> 1001      # lineno of last read
static VALUE
rb_io_set_lineno(VALUE io, VALUE lineno)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    fptr->lineno = NUM2INT(lineno);
    return lineno;
}

lines(*args)

这是一个不推荐的别名each_line

static VALUE
rb_io_lines(int argc, VALUE *argv, VALUE io)
{
    rb_warn("IO#lines is deprecated; use #each_line instead");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
    return rb_io_each_line(argc, argv, io);
}

noecho {|io| }

产量self与禁用回声返回。

STDIN.noecho(&:gets)

将读取并返回一个没有回显的行。

您必须要求'io/console'才能使用此方法。

static VALUE
console_noecho(VALUE io)
{
    return ttymode(io, rb_yield, set_noecho, NULL);
}

nonblock {|io| } → io

nonblock(boolean) {|io| } → io

self非阻塞模式产量。

false作为参数给出时,self在阻塞模式下产生。原始模式在块执行后恢复。

static VALUE
rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
{
    int nb = 1;
    rb_io_t *fptr;
    int f, restore[2];

    GetOpenFile(io, fptr);
    if (argc > 0) {
        VALUE v;
        rb_scan_args(argc, argv, "01", &v);
        nb = RTEST(v);
    }
    f = io_nonblock_mode(fptr->fd);
    restore[0] = fptr->fd;
    restore[1] = f;
    if (!io_nonblock_set(fptr->fd, f, nb))
        return rb_yield(io);
    return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
}

nonblock = boolean → boolean

当设定为在流启用非阻塞模式true,并且当设定为阻塞模式false

static VALUE
rb_io_nonblock_set(VALUE io, VALUE nb)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (RTEST(nb))
        rb_io_set_nonblock(fptr);
    else
        io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
    return io;
}

nonblock? → boolean

返回trueIO对象是否处于非阻塞模式。

static VALUE
rb_io_nonblock_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (io_nonblock_mode(fptr->fd) & O_NONBLOCK)
        return Qtrue;
    return Qfalse;
}

nread → int

返回可以不阻塞地读取的字节数。如果没有可用信息,则返回零。

static VALUE
io_nread(VALUE io)
{
    rb_io_t *fptr;
    int len;
    ioctl_arg n;

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    len = rb_io_read_pending(fptr);
    if (len > 0) return INT2FIX(len);
    if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
    if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
    if (n > 0) return ioctl_arg2num(n);
    return INT2FIX(0);
}

oflush

在内核中刷新输出缓冲区。

您必须要求'io/console'才能使用此方法。

static VALUE
console_oflush(VALUE io)
{
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    if (tcflush(fd, TCOFLUSH)) rb_sys_fail(0);
#endif
    (void)fd;
    return io;
}

pathconf(p1)

使用fpathconf()返回路径名配置变量。

name应该是一个Etc始于其中的常量PC_

返回值是一个整数或零。零意味着无限期的限制。(fpathconf()返回-1,但未设置errno。)

require 'etc'
IO.pipe {|r, w|
  p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
}
static VALUE
io_pathconf(VALUE io, VALUE arg)
{
    int name;
    long ret;
    rb_io_t *fptr;

    name = NUM2INT(arg);

    GetOpenFile(io, fptr);

    errno = 0;
    ret = fpathconf(fptr->fd, name);
    if (ret == -1) {
        if (errno == 0) /* no limit */
            return Qnil;
        rb_sys_fail("fpathconf");
    }
    return LONG2NUM(ret);
}

pid → integer

返回与ios关联的子进程的进程ID 。这将由设置IO.popen

pipe = IO.popen("-")
if pipe
  $stderr.puts "In parent, child pid is #{pipe.pid}"
else
  $stderr.puts "In child, pid is #{$$}"
end

produces:

In child, pid is 26209
In parent, child pid is 26209
static VALUE
rb_io_pid(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (!fptr->pid)
        return Qnil;
    return PIDT2NUM(fptr->pid);
}

pos → integer

返回ios的当前偏移量(以字节为单位)。

f = File.new("testfile")
f.pos    #=> 0
f.gets   #=> "This is line one\n"
f.pos    #=> 17
static VALUE
rb_io_tell(VALUE io)
{
    rb_io_t *fptr;
    off_t pos;

    GetOpenFile(io, fptr);
    pos = io_tell(fptr);
    if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
    pos -= fptr->rbuf.len;
    return OFFT2NUM(pos);
}

pos = integer → integer

ios中寻找给定的位置(以字节为单位)。当ios是textmode 时,不能保证找到正确的位置。

f = File.new("testfile")
f.pos = 17
f.gets   #=> "This is line two\n"
static VALUE
rb_io_set_pos(VALUE io, VALUE offset)
{
    rb_io_t *fptr;
    off_t pos;

    pos = NUM2OFFT(offset);
    GetOpenFile(io, fptr);
    pos = io_seek(fptr, pos, SEEK_SET);
    if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);

    return OFFT2NUM(pos);
}

pressed?(p1)

static VALUE
console_key_pressed_p(VALUE io, VALUE k)
{
    int vk = -1;

    if (FIXNUM_P(k)) {
        vk = NUM2UINT(k);
    }
    else {
        const struct vktable *t;
        const char *kn;
        if (SYMBOL_P(k)) {
            k = rb_sym2str(k);
            kn = RSTRING_PTR(k);
        }
        else {
            kn = StringValuePtr(k);
        }
        t = console_win32_vk(kn, RSTRING_LEN(k));
        if (!t || (vk = (short)t->vk) == -1) {
            rb_raise(rb_eArgError, "unknown virtual key code: % "PRIsVALUE, k);
        }
    }
    return GetKeyState(vk) & 0x80 ? Qtrue : Qfalse;
}

print → nil

print(obj, ...) → nil

将给定的对象写入ios。返回nil

该流必须打开才能写入。每个给定的不是字符串的对象都将通过调用它的to_s方法进行转换。当没有参数被调用时,打印内容$_

如果输出字段分隔符($,)不是nil,则将其插入对象之间。如果输出记录separator($\)不是nil,则会将其附加到输出。

$stdout.print("This is ", 100, " percent.\n")

生产:

This is 100 percent.
VALUE
rb_io_print(int argc, const VALUE *argv, VALUE out)
{
    int i;
    VALUE line;

    /* if no argument given, print `$_' */
    if (argc == 0) {
        argc = 1;
        line = rb_lastline_get();
        argv = &line;
    }
    for (i=0; i<argc; i++) {
        if (!NIL_P(rb_output_fs) && i>0) {
            rb_io_write(out, rb_output_fs);
        }
        rb_io_write(out, argv[i]);
    }
    if (argc > 0 && !NIL_P(rb_output_rs)) {
        rb_io_write(out, rb_output_rs);
    }

    return Qnil;
}

printf(format_string , obj, ...) → nil

格式化并写入ios,在格式字符串的控制下转换参数。详情请参阅Kernel#sprintf

VALUE
rb_io_printf(int argc, const VALUE *argv, VALUE out)
{
    rb_io_write(out, rb_f_sprintf(argc, argv));
    return Qnil;
}

putc(obj) → obj

如果OBJNumeric,写其代码是最不显著字节字符OBJ,否则写的字符串表示的第一个字节OBJIOS。注意:此方法不适用于多字节字符,因为它会截断它们。

$stdout.putc "A"
$stdout.putc 65

生产:

AA
static VALUE
rb_io_putc(VALUE io, VALUE ch)
{
    VALUE str;
    if (RB_TYPE_P(ch, T_STRING)) {
        str = rb_str_substr(ch, 0, 1);
    }
    else {
        char c = NUM2CHR(ch);
        str = rb_str_new(&c, 1);
    }
    rb_io_write(io, str);
    return ch;
}

puts(obj, ...) → nil

写入给定的对象(一个或多个),以IOSIO#print。在没有以换行符结束的任何之后写入换行符。

如果使用数组参数调用,则将每个元素写入新行。如果不带参数调用,则输出一个换行符。

$stdout.puts("this", "is", "a", "test")

produces:

this
is
a
test
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
    int i;
    VALUE line;

    /* if no argument given, print newline. */
    if (argc == 0) {
        rb_io_write(out, rb_default_rs);
        return Qnil;
    }
    for (i=0; i<argc; i++) {
        if (RB_TYPE_P(argv[i], T_STRING)) {
            line = argv[i];
            goto string;
        }
        if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
            continue;
        }
        line = rb_obj_as_string(argv[i]);
      string:
        rb_io_write(out, line);
        if (RSTRING_LEN(line) == 0 ||
            !str_end_with_asciichar(line, '\n')) {
            rb_io_write(out, rb_default_rs);
        }
    }

    return Qnil;
}

raw(min: nil, time: nil) {|io| }

self原始模式下的产量。

STDIN.raw(&:gets)

将读取并返回一个没有回显和行编辑的行。

您必须要求'io/console'才能使用此方法。

static VALUE
console_raw(int argc, VALUE *argv, VALUE io)
{
    rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);
    return ttymode(io, rb_yield, set_rawmode, optp);
}

raw!(min: nil, time: nil)

启用原始模式。

如果终端模式需要返回,请使用io.raw {...}。

您必须要求'io/console'才能使用此方法。

static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;
    rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    set_rawmode(&t, optp);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

read([length , outbuf]) → string, outbuf, or nil

从I/O流中读取长度字节。

长度必须是非负整数或nil

如果长度是一个正整数,它会尝试读取长度字节而不进行任何转换(二进制模式)。它返回nil或一个字符串,其长度为1至长度字节。nil意味着它在开始时遇到了EOF。1到长度为 -1字节的字符串表示在读取结果后它符合EOF。该长度的字节串意味着它不符合EOF。结果字符串始终是ASCII-8BIT编码。

如果长度被忽略或者是nil,它将读取直到EOF和编码转换被应用。即使在开始时遇到EOF,它也会返回一个字符串。

如果长度为零,则返回""

如果可选的outbuf参数存在,它必须引用一个String,它将接收数据。该outbuf中仅包含方法调用后接收到的数据,即使它不是在一开始是空的。

在文件结尾,它返回nil""取决于长度ios.read()ios.read(nil)""并返回。ios.read(positive-integer)返回nil

f = File.new("testfile")
f.read(16)   #=> "This is line one"

# reads whole file
open("file") {|f|
  data = f.read # This returns a string even if the file is empty.
  ...
}

# iterate over fixed length records.
open("fixed-record-file") {|f|
  while record = f.read(256)
    ...
  end
}

# iterate over variable length records.
# record is prefixed by 32-bit length.
open("variable-record-file") {|f|
  while len = f.read(4)
    len = len.unpack("N")[0] # 32-bit length
    record = f.read(len) # This returns a string even if len is 0.
  end
}

请注意,此方法的行为与C中的fread()函数相同。这意味着它会重试以调用read(2)系统调用以读取具有指定长度(或直到EOF)的数据。即使ios是非阻塞模式,此行为也会被保留。(与其他方法一样,此方法对非阻塞标志不敏感)。如果您需要像read read(2)系统调用那样的行为,请考虑readpartial,#read_nonblock和sysread。

static VALUE
io_read(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    long n, len;
    VALUE length, str;
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    int previous_mode;
#endif

    rb_scan_args(argc, argv, "02", &length, &str);

    if (NIL_P(length)) {
        GetOpenFile(io, fptr);
        rb_io_check_char_readable(fptr);
        return read_all(fptr, remain_size(fptr), str);
    }
    len = NUM2LONG(length);
    if (len < 0) {
        rb_raise(rb_eArgError, "negative length %ld given", len);
    }

    io_setstrbuf(&str,len);

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    if (len == 0) {
        io_set_read_length(str, 0);
        return str;
    }

    READ_CHECK(fptr);
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    previous_mode = set_binary_mode_with_seek_cur(fptr);
#endif
    n = io_fread(str, 0, len, fptr);
    io_set_read_length(str, n);
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (previous_mode == O_TEXT) {
        setmode(fptr->fd, O_TEXT);
    }
#endif
    if (n == 0) return Qnil;
    OBJ_TAINT(str);

    return str;
}

read_nonblock(maxlen , options) → string

read_nonblock(maxlen, outbuf , options) → outbuf

在为基础文件描述符设置O_NONBLOCK后,使用read(2)系统调用从ios读取至多maxlen字节。

如果可选的outbuf参数存在,它必须引用一个String,它将接收数据。该outbuf中仅包含方法调用后接收到的数据,即使它不是在一开始是空的。

#read_nonblock只是调用read(2)系统调用。它会导致read(2)系统调用导致的所有错误:Errno::EWOULDBLOCK,Errno::EINTR等。调用者应该关心这样的错误。

如果该异常是Errno::EWOULDBLOCK或Errno::EAGAIN,则它由IO::WaitReadable扩展。所以IO::WaitReadable可以用来恢复重试read_nonblock的异常。

#read_nonblock在EOF上导致EOFError。

如果读取的字节缓冲区不是空的,#read_nonblock像readpartial那样从缓冲区读取数据。在这种情况下,不会调用read(2)系统调用。

当#read_nonblock引发一个IO::WaitReadable类型的异常时,在读取io以避免繁忙循环之前,不应调用#read_nonblock。这可以如下完成。

# emulates blocking read (readpartial).
begin
  result = io.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io])
  retry
end

尽管#read_nonblock不会引发IO::WaitWritable。OpenSSL::Buffering#read_nonblock可以引发IO::WaitWritable。如果IO和SSL应该多态使用,IO::WaitWritable也应该被救出。查看示例代码的OpenSSL::Buffering#read_nonblock文档。

请注意,除非设置了非阻塞标志,否则此方法与readpartial相同。

通过指定关键字参数异常false,你可以指出#read_nonblock应该不会引发IO :: WaitReadable异常,但返回的符号:wait_readable来代替。在EOF中,它将返回nil而不是引发EOFError。

# File prelude.rb, line 75
def read_nonblock(len, buf = nil, exception: true)
  __read_nonblock(len, buf, exception)
end

readbyte → integer

像读取一个字节一样IO#getbyte,但会引起EOFError文件结束。

static VALUE
rb_io_readbyte(VALUE io)
{
    VALUE c = rb_io_getbyte(io);

    if (NIL_P(c)) {
        rb_eof_error();
    }
    return c;
}

readchar → string

ios读取一个字符的字符串。引发EOFError文件结尾。

f = File.new("testfile")
f.readchar   #=> "h"
f.readchar   #=> "e"
static VALUE
rb_io_readchar(VALUE io)
{
    VALUE c = rb_io_getc(io);

    if (NIL_P(c)) {
        rb_eof_error();
    }
    return c;
}

readline(sep=$/) → string

readline(limit) → string

readline(sep, limit) → string

读取一行IO#gets,但引发EOFError文件结束。

static VALUE
rb_io_readline(int argc, VALUE *argv, VALUE io)
{
    VALUE line = rb_io_gets_m(argc, argv, io);

    if (NIL_P(line)) {
        rb_eof_error();
    }
    return line;
}

readlines(sep=$/) → array

readlines(limit) → array

readlines(sep, limit) → array

读取ios中的所有行,并将它们返回到数组中。行由可选的sep分隔。如果九月nil,流的其余部分被返回为单个记录。如果第一个参数是一个整数,或者给出了可选的第二个参数,则返回的字符串不会超过以字节为单位的给定值。该流必须打开阅读或IOError将被提出。

f = File.new("testfile")
f.readlines[0]   #=> "This is line one\n"
static VALUE
rb_io_readlines(int argc, VALUE *argv, VALUE io)
{
    struct getline_arg args;

    prepare_getline_args(argc, argv, &args, io);
    return io_readlines(&args, io);
}

readpartial(maxlen) → string

readpartial(maxlen, outbuf) → outbuf

从I / O流中最多读取maxlen字节。它仅在ios没有立即可用数据时阻塞。如果有一些数据可用,它不会阻止。如果可选的outbuf参数存在,它必须引用一个String,它将接收数据。该outbuf中仅包含方法调用后接收到的数据,即使它不是在一开始是空的。它EOFError在文件结尾处引发。

readpartial是为诸如管道,套接字,tty等流设计的,只有当没有数据立即可用时才会阻塞。这意味着它只有在遵循所有条件时才会阻止。

  • IO对象中的字节缓冲区为空。
  • 流的内容是空的。
  • 流未达到EOF。当读取部分块时,它等待流上的数据或EOF。如果达到某些数据,readpartial将返回数据。如果达到EOF,则readpartial引发EOFError。当readpartial不阻塞时,它立即返回或提升。如果字节缓冲区不是空的,它将返回缓冲区中的数据。否则,如果流有一些内容,它将返回流中的数据。否则,如果数据流达到EOF,则会引发EOFError.r,w = IO.pipe#buffer pipe content w <<“abc”#“”“abc”。r.readpartial(4096)#=>“abc”“”“”r.readpartial(4096)#blocks因为缓冲区和管道是空的。r,w = 10。readpartial(4096)#=>“ghi \ n”“”“”请注意,readpartial的行为类似于sysread。差异是:
  • 如果字节缓冲区不为空,则从字节缓冲区读取而不是“缓冲IO(IOError)的系统读取”。
  • 它不会导致Errno::EWOULDBLOCK和Errno::EINTR。当readpartial通过读系统调用遇到EWOULDBLOCK和EINTR时,readpartial重试系统调用。

后者意味着readpartial是非阻塞标志不敏感的。它阻止#sysread导致Errno::EWOULDBLOCK的情况,就好像fd是阻塞模式一样。

static VALUE
io_readpartial(int argc, VALUE *argv, VALUE io)
{
    VALUE ret;

    ret = io_getpartial(argc, argv, io, Qnil, 0);
    if (NIL_P(ret))
        rb_eof_error();
    return ret;
}

ready? → true, false or nil

如果输入可用而不阻塞,则返回true;否则返回false。如果没有可用信息,则返回nil。

static VALUE
io_ready_p(VALUE io)
{
    rb_io_t *fptr;
    struct timeval tv = {0, 0};

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    if (rb_io_read_pending(fptr)) return Qtrue;
    if (wait_for_single_fd(fptr, RB_WAITFD_IN, &tv))
        return Qtrue;
    return Qfalse;
}

reopen(other_IO) → ios

reopen(path, mode_str) → ios

iosother_IO中给出的I/O流重新关联,或重新关联路径上打开的新流。这可能动态地改变这个流的实际类别。

f1 = File.new("testfile")
f2 = File.new("testfile")
f2.readlines[0]   #=> "This is line one\n"
f2.reopen(f1)     #=> #<File:testfile>
f2.readlines[0]   #=> "This is line one\n"
static VALUE
rb_io_reopen(int argc, VALUE *argv, VALUE file)
{
    VALUE fname, nmode, opt;
    int oflags;
    rb_io_t *fptr;

    if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
        VALUE tmp = rb_io_check_io(fname);
        if (!NIL_P(tmp)) {
            return io_reopen(file, tmp);
        }
    }

    FilePathValue(fname);
    rb_io_taint_check(file);
    fptr = RFILE(file)->fptr;
    if (!fptr) {
        fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
    }

    if (!NIL_P(nmode) || !NIL_P(opt)) {
        int fmode;
        convconfig_t convconfig;

        rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
        if (IS_PREP_STDIO(fptr) &&
            ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
            (fptr->mode & FMODE_READWRITE)) {
            rb_raise(rb_eArgError,
                     "%s can't change access mode from \"%s\" to \"%s\"",
                     PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
                     rb_io_fmode_modestr(fmode));
        }
        fptr->mode = fmode;
        fptr->encs = convconfig;
    }
    else {
        oflags = rb_io_fmode_oflags(fptr->mode);
    }

    fptr->pathv = fname;
    if (fptr->fd < 0) {
        fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
        fptr->stdio_file = 0;
        return file;
    }

    if (fptr->mode & FMODE_WRITABLE) {
        if (io_fflush(fptr) < 0)
            rb_sys_fail(0);
    }
    fptr->rbuf.off = fptr->rbuf.len = 0;

    if (fptr->stdio_file) {
        int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
                           rb_io_oflags_modestr(oflags),
                           fptr->stdio_file);
        if (e) rb_syserr_fail_path(e, fptr->pathv);
        fptr->fd = fileno(fptr->stdio_file);
        rb_fd_fix_cloexec(fptr->fd);
#ifdef USE_SETVBUF
        if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
            rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
#endif
        if (fptr->stdio_file == stderr) {
            if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
                rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
        }
        else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
            if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
                rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
        }
    }
    else {
        int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
        int err = 0;
        if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
            err = errno;
        (void)close(tmpfd);
        if (err) {
            rb_syserr_fail_path(err, fptr->pathv);
        }
    }

    return file;
}

rewind → 0

ios置于输入的开头,重置lineno为零。

f = File.new("testfile")
f.readline   #=> "This is line one\n"
f.rewind     #=> 0
f.lineno     #=> 0
f.readline   #=> "This is line one\n"

请注意,它不能用于诸如管道,ttys和套接字之类的流。

static VALUE
rb_io_rewind(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
    if (io == ARGF.current_file) {
        ARGF.lineno -= fptr->lineno;
    }
    fptr->lineno = 0;
    if (fptr->readconv) {
        clear_readconv(fptr);
    }

    return INT2FIX(0);
}

scanf(str) { |current_match| ... }

扫描当前字符串,直到匹配耗尽,在字符串中遇到每个匹配时产生每个匹配。一个块不是必需的,因为结果将被简单地聚合到最终的数组中。

"123 456".block_scanf("%d")
# => [123, 456]

如果给出了块,则从yield返回的值将被添加到输出数组中。

"123 456".block_scanf("%d") do |digit,| # the ',' unpacks the Array
  digit + 100
end
# => [223, 556]

有关创建格式字符串的详细信息,请参阅Scanf。

你将需要'scanf'来使用#scanf。

# File lib/scanf.rb, line 613
def scanf(str,&b) #:yield: current_match
  return block_scanf(str,&b) if b
  return [] unless str.size > 0

  start_position = pos rescue 0
  matched_so_far = 0
  source_buffer = ""
  result_buffer = []
  final_result = []

  fstr = Scanf::FormatString.new(str)

  loop do
    if eof || (tty? &&! fstr.match(source_buffer))
      final_result.concat(result_buffer)
      break
    end

    source_buffer << gets

    current_match = fstr.match(source_buffer)

    spec = fstr.last_spec_tried

    if spec.matched
      if spec.mid_match?
        result_buffer.replace(current_match)
        next
      end

    elsif (fstr.matched_count == fstr.spec_count - 1)
      if /\A\s*\z/.match(fstr.string_left)
        break if spec.count_space?
        result_buffer.replace(current_match)
        next
      end
    end

    final_result.concat(current_match)

    matched_so_far += source_buffer.size
    source_buffer.replace(fstr.string_left)
    matched_so_far -= source_buffer.size
    break if fstr.last_spec
    fstr.prune
  end

  begin
    seek(start_position + matched_so_far, IO::SEEK_SET)
  rescue Errno::ESPIPE
  end

  soak_up_spaces if fstr.last_spec && fstr.space

  return final_result
end

seek(amount, whence=IO::SEEK_SET) → 0 Show source

根据whence的值寻找流中给定的偏移anInteger

:CUR or IO::SEEK_CUR  | Seeks to _amount_ plus current position
----------------------+--------------------------------------------------
:END or IO::SEEK_END  | Seeks to _amount_ plus end of stream (you
                      | probably want a negative value for _amount_)
----------------------+--------------------------------------------------
:SET or IO::SEEK_SET  | Seeks to the absolute location given by _amount_

例:

f = File.new("testfile")
f.seek(-13, IO::SEEK_END)   #=> 0
f.readline                  #=> "And so on...\n"
static VALUE
rb_io_seek_m(int argc, VALUE *argv, VALUE io)
{
    VALUE offset, ptrname;
    int whence = SEEK_SET;

    if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
        whence = interpret_seek_whence(ptrname);
    }

    return rb_io_seek(io, offset, whence);
}

set_encoding(ext_enc) → io

set_encoding("ext_enc:int_enc") → io

set_encoding(ext_enc, int_enc) → io

set_encoding("ext_enc:int_enc", opt) → io

set_encoding(ext_enc, int_enc, opt) → io

如果指定单参数,则从io读取的字符串将使用指定的编码进行标记。如果编码是以冒号分隔的两个编码名称“A:B”,则读取的字符串从编码A(外部编码)转换为编码B(内部编码),然后用B标记。如果指定了两个参数,则这些参数必须是编码对象或编码名称,第一个是外部编码,第二个是内部编码。如果指定了外部编码和内部编码,则可选散列参数指定转换选项。

static VALUE
rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    VALUE v1, v2, opt;

    if (!RB_TYPE_P(io, T_FILE)) {
        return rb_funcallv(io, id_set_encoding, argc, argv);
    }

    argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
    GetOpenFile(io, fptr);
    io_encoding_set(fptr, v1, v2, opt);
    return io;
}

stat → stat

ios的状态信息作为类型的对象返回File::Stat

f = File.new("testfile")
s = f.stat
"%o" % s.mode   #=> "100644"
s.blksize       #=> 4096
s.atime         #=> Wed Apr 09 08:53:54 CDT 2003
static VALUE
rb_io_stat(VALUE obj)
{
    rb_io_t *fptr;
    struct stat st;

    GetOpenFile(obj, fptr);
    if (fstat(fptr->fd, &st) == -1) {
        rb_sys_fail_path(fptr->pathv);
    }
    return rb_stat_new(&st);
}

sync → true or false

返回ios的当前“同步模式” 。当同步模式为true时,所有输出将立即刷新到底层操作系统,而不会由Ruby在内部进行缓冲。另见IO#fsync

f = File.new("testfile")
f.sync   #=> false
static VALUE
rb_io_sync(VALUE io)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
}

sync = boolean → boolean

将“同步模式”设置为truefalse。当同步模式为真时,所有输出立即刷新到底层操作系统,而不会在内部进行缓冲。返回新的状态。另见IO#fsync

f = File.new("testfile")
f.sync = true
static VALUE
rb_io_set_sync(VALUE io, VALUE sync)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    if (RTEST(sync)) {
        fptr->mode |= FMODE_SYNC;
    }
    else {
        fptr->mode &= ~FMODE_SYNC;
    }
    return sync;
}

sysread(maxlen, outbuf) → string

使用低级读取从ios读取maxlen字节并将其作为字符串返回。不要与从ios读取的其他方法混用,否则可能会得到不可预知的结果。如果可选的outbuf参数存在,它必须引用一个String,它将接收数据。该outbuf中仅包含方法调用后接收到的数据,即使它不是在一开始是空的。在错误和文件结尾处引发。SystemCallErrorEOFError

f = File.new("testfile")
f.sysread(16)   #=> "This is line one"
static VALUE
rb_io_sysread(int argc, VALUE *argv, VALUE io)
{
    VALUE len, str;
    rb_io_t *fptr;
    long n, ilen;
    struct read_internal_arg arg;

    rb_scan_args(argc, argv, "11", &len, &str);
    ilen = NUM2LONG(len);

    io_setstrbuf(&str,ilen);
    if (ilen == 0) return str;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);

    if (READ_DATA_BUFFERED(fptr)) {
        rb_raise(rb_eIOError, "sysread for buffered IO");
    }

    /*
     * FIXME: removing rb_thread_wait_fd() here changes sysread semantics
     * on non-blocking IOs.  However, it's still currently possible
     * for sysread to raise Errno::EAGAIN if another thread read()s
     * the IO after we return from rb_thread_wait_fd() but before
     * we call read()
     */
    rb_thread_wait_fd(fptr->fd);

    rb_io_check_closed(fptr);

    io_setstrbuf(&str, ilen);
    rb_str_locktmp(str);
    arg.fd = fptr->fd;
    arg.str_ptr = RSTRING_PTR(str);
    arg.len = ilen;
    rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
    n = arg.len;

    if (n == -1) {
        rb_sys_fail_path(fptr->pathv);
    }
    io_set_read_length(str, n);
    if (n == 0 && ilen > 0) {
        rb_eof_error();
    }
    OBJ_TAINT(str);

    return str;
}

sysseek(offset, whence=IO::SEEK_SET) → integer

旨在给定偏移量根据所述值的流中的何处(参看IO#seek为值何处)。返回文件中的新偏移量。

f = File.new("testfile")
f.sysseek(-13, IO::SEEK_END)   #=> 53
f.sysread(10)                  #=> "And so on."
static VALUE
rb_io_sysseek(int argc, VALUE *argv, VALUE io)
{
    VALUE offset, ptrname;
    int whence = SEEK_SET;
    rb_io_t *fptr;
    off_t pos;

    if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
        whence = interpret_seek_whence(ptrname);
    }
    pos = NUM2OFFT(offset);
    GetOpenFile(io, fptr);
    if ((fptr->mode & FMODE_READABLE) &&
        (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
        rb_raise(rb_eIOError, "sysseek for buffered IO");
    }
    if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
        rb_warn("sysseek for buffered IO");
    }
    errno = 0;
    pos = lseek(fptr->fd, pos, whence);
    if (pos == -1 && errno) rb_sys_fail_path(fptr->pathv);

    return OFFT2NUM(pos);
}

syswrite(string) → integer

使用低级写入将给定的字符串写入ios。返回写入的字节数。不要与写入ios的其他方法混用,否则可能会得到不可预知的结果。SystemCallError错误引发。

f = File.new("out", "w")
f.syswrite("ABCDEF")   #=> 6
static VALUE
rb_io_syswrite(VALUE io, VALUE str)
{
    VALUE tmp;
    rb_io_t *fptr;
    long n, len;
    const char *ptr;

    if (!RB_TYPE_P(str, T_STRING))
        str = rb_obj_as_string(str);

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    rb_io_check_writable(fptr);

    if (fptr->wbuf.len) {
        rb_warn("syswrite for buffered IO");
    }

    tmp = rb_str_tmp_frozen_acquire(str);
    RSTRING_GETMEM(tmp, ptr, len);
    n = rb_write_internal(fptr->fd, ptr, len);
    if (n == -1) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return LONG2FIX(n);
}

tell → integer

返回ios的当前偏移量(以字节为单位)。

f = File.new("testfile")
f.pos    #=> 0
f.gets   #=> "This is line one\n"
f.pos    #=> 17
static VALUE
rb_io_tell(VALUE io)
{
    rb_io_t *fptr;
    off_t pos;

    GetOpenFile(io, fptr);
    pos = io_tell(fptr);
    if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
    pos -= fptr->rbuf.len;
    return OFFT2NUM(pos);
}

to_i()

别名为:fileno

to_io → ios

返回ios

static VALUE
rb_io_to_io(VALUE io)
{
    return io;
}

tty?→true或false显示来源

如果ios与终端设备(tty)关联则返回true,否则返回false

File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true
static VALUE
rb_io_isatty(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (isatty(fptr->fd) == 0)
        return Qfalse;
    return Qtrue;
}

ungetbyte(string) → nil

ungetbyte(integer) → nil

将字节(作为参数传递)推回到ios上,以便随后的缓冲读取将返回它。在后续的读取操作之前,只有一个字节可能被推回(也就是说,您将只能读取已被推回的几个字节中的最后一个字节)。对未缓冲的读取(例如IO#sysread)没有影响。

f = File.new("testfile")   #=> #<File:testfile>
b = f.getbyte              #=> 0x38
f.ungetbyte(b)             #=> nil
f.getbyte                  #=> 0x38
VALUE
rb_io_ungetbyte(VALUE io, VALUE b)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    if (NIL_P(b)) return Qnil;
    if (FIXNUM_P(b)) {
        char cc = FIX2INT(b);
        b = rb_str_new(&cc, 1);
    }
    else {
        SafeStringValue(b);
    }
    io_ungetbyte(b, fptr);
    return Qnil;
}

ungetc(string) → nil

将一个字符(作为参数传递)推回到ios上,以便后续的缓存字符读取将返回它。在后续的读取操作之前,只有一个字符可能会被推回(也就是说,您将只能读取已被推回的几个字符中的最后一个字符)。对未缓冲的读取(例如IO#sysread)没有影响。

f = File.new("testfile")   #=> #<File:testfile>
c = f.getc                 #=> "8"
f.ungetc(c)                #=> nil
f.getc                     #=> "8"
VALUE
rb_io_ungetc(VALUE io, VALUE c)
{
    rb_io_t *fptr;
    long len;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    if (NIL_P(c)) return Qnil;
    if (FIXNUM_P(c)) {
        c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
    }
    else if (RB_TYPE_P(c, T_BIGNUM)) {
        c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
    }
    else {
        SafeStringValue(c);
    }
    if (NEED_READCONV(fptr)) {
        SET_BINARY_MODE(fptr);
        len = RSTRING_LEN(c);
#if SIZEOF_LONG > SIZEOF_INT
        if (len > INT_MAX)
            rb_raise(rb_eIOError, "ungetc failed");
#endif
        make_readconv(fptr, (int)len);
        if (fptr->cbuf.capa - fptr->cbuf.len < len)
            rb_raise(rb_eIOError, "ungetc failed");
        if (fptr->cbuf.off < len) {
            MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
                    fptr->cbuf.ptr+fptr->cbuf.off,
                    char, fptr->cbuf.len);
            fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
        }
        fptr->cbuf.off -= (int)len;
        fptr->cbuf.len += (int)len;
        MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
    }
    else {
        NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
        io_ungetbyte(c, fptr);
    }
    return Qnil;
}

wait(timeout = nil, mode = :read) → IO, true or nil

一直等到IO可读或可写,而不会阻塞并返回self,或者nil超时。true缓冲数据可用时立即返回。可选参数mode是一个:read:write:read_write

static VALUE
io_wait_readwrite(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    struct timeval timerec;
    struct timeval *tv = NULL;
    int event = 0;
    int i;

    GetOpenFile(io, fptr);
    for (i = 0; i < argc; ++i) {
        if (SYMBOL_P(argv[i])) {
            event |= wait_mode_sym(argv[i]);
        }
        else {
            *(tv = &timerec) = rb_time_interval(argv[i]);
        }
    }
    /* rb_time_interval() and might_mode() might convert the argument */
    rb_io_check_closed(fptr);
    if (!event) event = RB_WAITFD_IN;
    if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
        return Qtrue;
    if (wait_for_single_fd(fptr, event, tv))
        return io;
    return Qnil;
}

wait_readable → IO, true or nil

wait_readable(timeout) → IO, true or nil

等到IO可读而没有阻塞并返回self,或者nil超时。缓冲数据可用时立即返回true

static VALUE
io_wait_readable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    struct timeval timerec;
    struct timeval *tv;

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    tv = get_timeout(argc, argv, &timerec);
    if (rb_io_read_pending(fptr)) return Qtrue;
    if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
        return io;
    }
    return Qnil;
}

wait_writable → IO

wait_writable(timeout) → IO or nil

等到IO可写且没有阻塞并返回selfnil超时。

static VALUE
io_wait_writable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    struct timeval timerec;
    struct timeval *tv;

    GetOpenFile(io, fptr);
    rb_io_check_writable(fptr);
    tv = get_timeout(argc, argv, &timerec);
    if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
        return io;
    }
    return Qnil;
}

winsize → rows, columns()

返回控制台大小。

您必须要求'io/console'才能使用此方法。

static VALUE
console_winsize(VALUE io)
{
    rb_io_t *fptr;
    int fd;
    rb_console_size_t ws;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    if (!getwinsize(fd, &ws)) rb_sys_fail(0);
    return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}

winsize = rows, columns()

尝试设置控制台大小。效果取决于平台和运行环境。

您必须要求'io/console'才能使用此方法。

static VALUE
console_set_winsize(VALUE io, VALUE size)
{
    rb_io_t *fptr;
    rb_console_size_t ws;
#if defined _WIN32
    HANDLE wh;
    int newrow, newcol;
#endif
    VALUE row, col, xpixel, ypixel;
    const VALUE *sz;
    int fd;
    long sizelen;

    GetOpenFile(io, fptr);
    size = rb_Array(size);
    if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
        rb_raise(rb_eArgError,
                 "wrong number of arguments (given %ld, expected 2 or 4)",
                 sizelen);
    }
    sz = RARRAY_CONST_PTR(size);
    row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
    if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
    fd = GetWriteFD(fptr);
#if defined TIOCSWINSZ
    ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
    SET(row);
    SET(col);
    SET(xpixel);
    SET(ypixel);
#undef SET
    if (!setwinsize(fd, &ws)) rb_sys_fail(0);
#elif defined _WIN32
    wh = (HANDLE)rb_w32_get_osfhandle(fd);
#define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
    SET(row);
    SET(col);
#undef SET
    if (!NIL_P(xpixel)) (void)NUM2UINT(xpixel);
    if (!NIL_P(ypixel)) (void)NUM2UINT(ypixel);
    if (!GetConsoleScreenBufferInfo(wh, &ws)) {
        rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
    }
    if ((ws.dwSize.X < newcol && (ws.dwSize.X = newcol, 1)) ||
        (ws.dwSize.Y < newrow && (ws.dwSize.Y = newrow, 1))) {
        if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) {
            rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
        }
    }
    ws.srWindow.Left = 0;
    ws.srWindow.Top = 0;
    ws.srWindow.Right = newcol;
    ws.srWindow.Bottom = newrow;
    if (!SetConsoleWindowInfo(wh, FALSE, &ws.srWindow)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
    }
#endif
    return io;
}

write(string) → integer

将给定的字符串写入ios。该流必须打开才能写入。如果参数不是字符串,它将被转换为使用的字符串to_s。返回写入的字节数。

count = $stdout.write("This is a test\n")
puts "That was #{count} bytes of data"

produces:

This is a test
That was 15 bytes of data
static VALUE
io_write_m(VALUE io, VALUE str)
{
    return io_write(io, str, 0);
}

write_nonblock(string) → integer

write_nonblock(string , options) → integer

在为基础文件描述符设置O_NONBLOCK后,使用write(2)系统调用将给定的字符串写入ios

它返回写入的字节数。

#write_nonblock只是调用write(2)系统调用。它会导致write(2)系统调用导致的所有错误:Errno::EWOULDBLOCK,Errno::EINTR等。结果也可能小于string.length(部分写入)。调用者应该关心这样的错误和部分写入。

如果该异常是Errno :: EWOULDBLOCK或Errno :: EAGAIN,则它由IO :: WaitWritable扩展。所以IO :: WaitWritable可以用来恢复重试write_nonblock的异常。

# Creates a pipe.
r, w = IO.pipe

# write_nonblock writes only 65536 bytes and return 65536.
# (The pipe size is 65536 bytes on this environment.)
s = "a" * 100000
p w.write_nonblock(s)     #=> 65536

# write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
p w.write_nonblock("b")   # Resource temporarily unavailable (Errno::EAGAIN)

如果写入缓冲区不是空的,它首先被刷新。

当#write_nonblock引发异常类型的IO::WaitWritable时,不应调用#write_nonblock,直到io可写,以避免繁忙循环。这可以如下完成。

begin
  result = io.write_nonblock(string)
rescue IO::WaitWritable, Errno::EINTR
  IO.select(nil, [io])
  retry
end

请注意,这并不保证写入字符串中的所有数据。写入的长度将作为结果报告,并且应在稍后检查。

在某些平台(如Windows)上,根据IO对象的种类不支持#write_nonblock。在这种情况下,#write_nonblock引发Errno::EBADF

通过指定关键字参数异常false,你可以指出#write_nonblock应该不会引发IO :: WaitWritable异常,但返回的符号:wait_writable来代替。

# File prelude.rb, line 133
def write_nonblock(buf, exception: true)
  __write_nonblock(buf, exception)
end

私有实例方法

block_scanf(str) { |current| ... }

# File lib/scanf.rb, line 681
  def block_scanf(str)
    final = []
# Sub-ideal, since another FS gets created in scanf.
# But used here to determine the number of specifiers.
    fstr = Scanf::FormatString.new(str)
    last_spec = fstr.last_spec
    begin
      current = scanf(str)
      break if current.empty?
      final.push(yield(current))
    end until eof || fstr.last_spec_tried == last_spec
    return final
  end

soak_up_spaces()

# File lib/scanf.rb, line 672
def soak_up_spaces
  c = getc
  ungetc(c) if c
  until eof ||! c || /\S/.match(c.chr)
    c = getc
  end
  ungetc(c) if (c && /\S/.match(c.chr))
end
IO
IO::generic_readable 详细
IO::generic_writable 详细
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct