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复制 到dst。src和dst是文件名或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_enc
和int_enc
被指定时,读取的字符串将从 输入转换ext_enc
为int_enc
,写入的字符串将从输出转换int_enc
为ext_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的的描述 fd
,mode
和opt
参数。
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_io,write_io ]
。
如果给出一个块,则调用该块并返回该块的值。read_io和write_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.)
如果cmd是String
“ -
”,那么Ruby的新实例将作为子进程启动。
如果CMD是Array
的String
,那么它将被用作子过程的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_nonblock
,write_nonblock
等。该方法提高其通过扩展一个异常 IO::WaitReadable
或IO::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.select
在IO#readpartial
平常工作之前调用。但它不是最好的使用方法 IO.select
。
select(2)通知的可写性不显示可写入多少字节。IO#write
方法阻塞,直到写入完整的字符串。所以,IO#write(two or more bytes)
可写性通知后可以阻塞IO.select
。IO#write_nonblock
需要避免阻塞。
阻塞写(write
)可以使用模拟 write_nonblock
和IO.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
字符串输出,写入OBJ到 IOS。obj将被转换为一个字符串使用 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,则该区域结束于文件的最后一个字节。默认情况下,offset和 len都是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.popen
,close
设置$?
。
从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| }
self
cooked模式下的产量。
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
返回true
IO对象是否处于非阻塞模式。
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
如果OBJ是Numeric
,写其代码是最不显著字节字符OBJ,否则写的字符串表示的第一个字节OBJ到IOS。注意:此方法不适用于多字节字符,因为它会截断它们。
$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
写入给定的对象(一个或多个),以IOS与IO#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
将ios与other_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
将“同步模式”设置为true
或false
。当同步模式为真时,所有输出立即刷新到底层操作系统,而不会在内部进行缓冲。返回新的状态。另见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可写且没有阻塞并返回self
或nil
超时。
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 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。
主页 | https://www.ruby-lang.org/ |
源码 | https://github.com/ruby/ruby |
版本 | 2.4 |
发布版本 | 2.4.1 |