类 ARGF
ARGF
是一个为在处理命令行参数或通过 STDIN 传递的文件的脚本中使用而设计的流。
传递给脚本的参数存储在 ARGV
Array
中,每个元素对应一个参数。 ARGF
假设所有不是文件名的参数都已从 ARGV
中删除。例如
$ ruby argf.rb --verbose file1 file2 ARGV #=> ["--verbose", "file1", "file2"] option = ARGV.shift #=> "--verbose" ARGV #=> ["file1", "file2"]
现在可以使用 ARGF
来处理这些命名文件的串联。例如,ARGF.read
将返回 file1 的内容,后跟 file2 的内容。
在 ARGV
中的一个文件被读取后,ARGF
会将其从 Array
中删除。因此,在所有文件都被读取后,ARGV
将为空。
可以自己操作 ARGV
来控制 ARGF
的操作对象。如果从 ARGV
中删除一个文件,ARGF
会忽略它;如果向 ARGV
添加文件,则会将其视为在命令行中命名一样。例如
ARGV.replace ["file1"] ARGF.readlines # Returns the contents of file1 as an Array ARGV #=> [] ARGV.replace ["file2", "file3"] ARGF.read # Returns the contents of file2 and file3
如果 ARGV
为空,ARGF
会像包含 "-"
一样,使 ARGF
从 STDIN 读取数据,即管道或输入到脚本中的数据。例如
$ echo "glark" | ruby -e 'p ARGF.read' "glark\n" $ echo Glark > file1 $ echo "glark" | ruby -e 'p ARGF.read' -- - file1 "glark\nGlark\n"
公共实例方法
返回 ARGV
数组,其中包含传递给脚本的参数,每个元素一个。
例如
$ ruby argf.rb -v glark.txt ARGF.argv #=> ["-v", "glark.txt"]
static VALUE argf_argv(VALUE argf) { return ARGF.argv; }
如果 ARGF
以二进制模式读取,则返回 true;否则返回 false。要启用二进制模式,请使用 ARGF.binmode
。
例如
ARGF.binmode? #=> false ARGF.binmode ARGF.binmode? #=> true
static VALUE argf_binmode_p(VALUE argf) { return RBOOL(ARGF.binmode); }
关闭当前文件并跳到 ARGV 中的下一个文件。如果没有更多文件要打开,则只关闭当前文件。STDIN 不会关闭。
例如
$ ruby argf.rb foo bar ARGF.filename #=> "foo" ARGF.close ARGF.filename #=> "bar" ARGF.close
static VALUE argf_close_m(VALUE argf) { next_argv(); argf_close(argf); if (ARGF.next_p != -1) { ARGF.next_p = 1; } ARGF.lineno = 0; return argf; }
如果当前文件已关闭,则返回 true;否则返回 false。使用 ARGF.close
实际关闭当前文件。
static VALUE argf_closed(VALUE argf) { next_argv(); ARGF_FORWARD(0, 0); return rb_io_closed_p(ARGF.current_file); }
返回一个枚举器,它迭代 ARGV
中每个文件中的每一行(以 sep 分隔,默认值为平台的换行符)。如果提供了一个块,则每一行依次将被传递给块,否则将返回一个枚举器。可选的 limit 参数是一个 Integer
,指定每行的最大长度;更长的行将根据此限制进行拆分。
此方法允许您将命令行上提供的文件视为单个文件,该文件由每个命名文件的串联组成。在返回第一个文件的最后一行后,将返回第二个文件的第一行。可以使用 ARGF.filename
和 ARGF.lineno
方法分别确定当前行的文件名和整个输入的行号。
例如,以下代码打印每个命名文件的每一行,并在其前面加上行号,每个文件显示一次文件名
ARGF.each_line do |line| puts ARGF.filename if ARGF.file.lineno == 1 puts "#{ARGF.file.lineno}: #{line}" end
虽然以下代码最初只打印第一个文件的文件名,但它会打印所有命名文件的内容,并对所有行进行编号。
ARGF.each_line do |line| puts ARGF.filename if ARGF.lineno == 1 puts "#{ARGF.lineno}: #{line}" end
static VALUE argf_each_line(int argc, VALUE *argv, VALUE argf) { RETURN_ENUMERATOR(argf, argc, argv); FOREACH_ARGF() { argf_block_call_line(rb_intern("each_line"), argc, argv, argf); } return argf; }
迭代 ARGV
中每个文件的每个字节。字节以 0..255 范围内的 Integer
返回。
此方法允许您将命令行上提供的文件视为单个文件,该文件由每个命名文件的串联组成。在返回第一个文件的最后一个字节后,将返回第二个文件的第一个字节。可以使用 ARGF.filename
方法来确定当前字节的文件名。
如果没有给出块,则返回一个枚举器。
例如
ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
static VALUE argf_each_byte(VALUE argf) { RETURN_ENUMERATOR(argf, 0, 0); FOREACH_ARGF() { argf_block_call(rb_intern("each_byte"), 0, 0, argf); } return argf; }
迭代 ARGF
中每个文件的每个字符。
此方法允许您将命令行上提供的文件视为单个文件,该文件由每个命名文件的串联组成。在返回第一个文件的最后一个字符后,将返回第二个文件的第一个字符。可以使用 ARGF.filename
方法来确定当前字符所在的当前文件名。
如果没有给出块,则返回一个枚举器。
static VALUE argf_each_char(VALUE argf) { RETURN_ENUMERATOR(argf, 0, 0); FOREACH_ARGF() { argf_block_call(rb_intern("each_char"), 0, 0, argf); } return argf; }
迭代 ARGF
中每个文件的每个码点。
此方法允许您将命令行上提供的文件视为单个文件,该文件由每个命名文件的串联组成。在返回第一个文件的最后一个码点后,将返回第二个文件的第一个码点。可以使用 ARGF.filename
方法来确定当前码点所在的当前文件名。
如果没有给出块,则返回一个枚举器。
static VALUE argf_each_codepoint(VALUE argf) { RETURN_ENUMERATOR(argf, 0, 0); FOREACH_ARGF() { argf_block_call(rb_intern("each_codepoint"), 0, 0, argf); } return argf; }
返回一个枚举器,它迭代 ARGV
中每个文件中的每一行(以 sep 分隔,默认值为平台的换行符)。如果提供了一个块,则每一行依次将被传递给块,否则将返回一个枚举器。可选的 limit 参数是一个 Integer
,指定每行的最大长度;更长的行将根据此限制进行拆分。
此方法允许您将命令行上提供的文件视为单个文件,该文件由每个命名文件的串联组成。在返回第一个文件的最后一行后,将返回第二个文件的第一行。可以使用 ARGF.filename
和 ARGF.lineno
方法分别确定当前行的文件名和整个输入的行号。
例如,以下代码打印每个命名文件的每一行,并在其前面加上行号,每个文件显示一次文件名
ARGF.each_line do |line| puts ARGF.filename if ARGF.file.lineno == 1 puts "#{ARGF.file.lineno}: #{line}" end
虽然以下代码最初只打印第一个文件的文件名,但它会打印所有命名文件的内容,并对所有行进行编号。
ARGF.each_line do |line| puts ARGF.filename if ARGF.lineno == 1 puts "#{ARGF.lineno}: #{line}" end
如果当前文件在 ARGF
中已到达文件末尾,即没有数据可读,则返回 true。流必须以读取模式打开,否则将引发 IOError
。
$ echo "eof" | ruby argf.rb ARGF.eof? #=> false 3.times { ARGF.readchar } ARGF.eof? #=> false ARGF.readchar #=> "\n" ARGF.eof? #=> true
static VALUE argf_eof(VALUE argf) { next_argv(); if (RTEST(ARGF.current_file)) { if (ARGF.init_p == 0) return Qtrue; next_argv(); ARGF_FORWARD(0, 0); if (rb_io_eof(ARGF.current_file)) { return Qtrue; } } return Qfalse; }
如果当前文件在 ARGF
中已到达文件末尾,即没有数据可读,则返回 true。流必须以读取模式打开,否则将引发 IOError
。
$ echo "eof" | ruby argf.rb ARGF.eof? #=> false 3.times { ARGF.readchar } ARGF.eof? #=> false ARGF.readchar #=> "\n" ARGF.eof? #=> true
将从 ARGF
读取的文件的外部编码作为 Encoding
对象返回。外部编码是文本在文件中存储时的编码。与 ARGF.internal_encoding
相反,后者是在 Ruby 中表示此文本的编码。
要设置外部编码,请使用 ARGF.set_encoding
。
例如
ARGF.external_encoding #=> #<Encoding:UTF-8>
static VALUE argf_external_encoding(VALUE argf) { return argf_encoding(argf, rb_io_external_encoding); }
返回当前文件名。当当前文件为 STDIN 时,返回“ - ”。
例如
$ echo "foo" > foo $ echo "bar" > bar $ echo "glark" > glark $ ruby argf.rb foo bar glark ARGF.filename #=> "foo" ARGF.read(5) #=> "foo\nb" ARGF.filename #=> "bar" ARGF.skip ARGF.filename #=> "glark"
static VALUE argf_filename(VALUE argf) { next_argv(); return ARGF.filename; }
返回一个整数,表示当前文件的数字文件描述符。如果不存在当前文件,则引发 ArgumentError
。
ARGF.fileno #=> 3
static VALUE argf_fileno(VALUE argf) { if (!next_argv()) { rb_raise(rb_eArgError, "no stream"); } ARGF_FORWARD(0, 0); return rb_io_fileno(ARGF.current_file); }
从 ARGF
获取下一个 8 位字节(0..255)。如果在流末尾调用,则返回 nil
。
例如
$ echo "foo" > file $ ruby argf.rb file ARGF.getbyte #=> 102 ARGF.getbyte #=> 111 ARGF.getbyte #=> 111 ARGF.getbyte #=> 10 ARGF.getbyte #=> nil
static VALUE argf_getbyte(VALUE argf) { VALUE ch; retry: if (!next_argv()) return Qnil; if (!RB_TYPE_P(ARGF.current_file, T_FILE)) { ch = forward_current(rb_intern("getbyte"), 0, 0); } else { ch = rb_io_getbyte(ARGF.current_file); } if (NIL_P(ch) && ARGF.next_p != -1) { argf_close(argf); ARGF.next_p = 1; goto retry; } return ch; }
从 ARGF
读取下一个字符,并将其作为 String
返回。在流末尾返回 nil
。
ARGF
将命令行上命名的文件视为一个单一文件,该文件通过连接其内容来创建。在返回第一个文件的最后一个字符后,它将返回第二个文件的第一个字符,依此类推。
例如
$ echo "foo" > file $ ruby argf.rb file ARGF.getc #=> "f" ARGF.getc #=> "o" ARGF.getc #=> "o" ARGF.getc #=> "\n" ARGF.getc #=> nil ARGF.getc #=> nil
static VALUE argf_getc(VALUE argf) { VALUE ch; retry: if (!next_argv()) return Qnil; if (ARGF_GENERIC_INPUT_P()) { ch = forward_current(rb_intern("getc"), 0, 0); } else { ch = rb_io_getc(ARGF.current_file); } if (NIL_P(ch) && ARGF.next_p != -1) { argf_close(argf); ARGF.next_p = 1; goto retry; } return ch; }
从当前文件中的 ARGF
返回下一行。
默认情况下,假设行以 $/
分隔;要使用其他字符作为分隔符,请将其作为 String
提供给 sep 参数。
可选的 limit 参数指定要返回的每行的字符数。默认情况下,返回所有字符。
有关 getline_args 的详细信息,请参阅 IO.readlines
。
static VALUE argf_gets(int argc, VALUE *argv, VALUE argf) { VALUE line; line = argf_getline(argc, argv, argf); rb_lastline_set(line); return line; }
返回在就地编辑模式下附加到修改后的文件的备份副本名称的文件扩展名。可以使用 ARGF.inplace_mode=
设置此值,或者将 -i
开关传递给 Ruby 二进制文件。
static VALUE argf_inplace_mode_get(VALUE argf) { if (!ARGF.inplace) return Qnil; if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0); return rb_str_dup(ARGF.inplace); }
将就地编辑模式的文件扩展名设置为给定的 String
。正在编辑的每个文件的备份副本在其文件名后附加此值。
例如
$ ruby argf.rb file.txt ARGF.inplace_mode = '.bak' ARGF.each_line do |line| print line.sub("foo","bar") end
首先,file.txt.bak 被创建为 file.txt 的备份副本。然后,file.txt 的每一行都将第一个出现的“foo”替换为“bar”。
static VALUE argf_inplace_mode_set(VALUE argf, VALUE val) { if (!RTEST(val)) { ARGF.inplace = Qfalse; } else if (StringValueCStr(val), !RSTRING_LEN(val)) { ARGF.inplace = Qnil; } else { ARGF.inplace = rb_str_new_frozen(val); } return argf; }
将从 ARGF
读取的字符串的内部编码作为 Encoding
对象返回。
如果 ARGF.set_encoding
已使用两个编码名称调用,则返回第二个编码名称。否则,如果已设置 Encoding.default_external
,则返回该值。如果失败,如果在命令行上指定了默认外部编码,则使用该值。如果编码未知,则返回 nil
。
static VALUE argf_internal_encoding(VALUE argf) { return argf_encoding(argf, rb_io_internal_encoding); }
将 ARGF
的当前行号作为整体返回。可以使用 ARGF.lineno=
手动设置此值。
例如
ARGF.lineno #=> 0 ARGF.readline #=> "This is line 1\n" ARGF.lineno #=> 1
static VALUE argf_lineno(VALUE argf) { return INT2FIX(ARGF.lineno); }
ARGF
在您读取数据时自动设置行号,因此通常您不需要显式设置它。要访问当前行号,请使用 ARGF.lineno
.
例如
ARGF.lineno #=> 0 ARGF.readline #=> "This is line 1\n" ARGF.lineno #=> 1 ARGF.lineno = 0 #=> 0 ARGF.lineno #=> 0
static VALUE argf_set_lineno(VALUE argf, VALUE val) { ARGF.lineno = NUM2INT(val); ARGF.last_lineno = ARGF.lineno; return val; }
返回当前文件名。当当前文件为 STDIN 时,返回“ - ”。
例如
$ echo "foo" > foo $ echo "bar" > bar $ echo "glark" > glark $ ruby argf.rb foo bar glark ARGF.filename #=> "foo" ARGF.read(5) #=> "foo\nb" ARGF.filename #=> "bar" ARGF.skip ARGF.filename #=> "glark"
返回 ARGF
中当前文件的当前偏移量(以字节为单位)。
ARGF.pos #=> 0 ARGF.gets #=> "This is line one\n" ARGF.pos #=> 17
在 ARGF
中,将位置设置为 position(以字节为单位)给出的位置。
例如
ARGF.pos = 17 ARGF.gets #=> "This is line two\n"
static VALUE argf_set_pos(VALUE argf, VALUE offset) { if (!next_argv()) { rb_raise(rb_eArgError, "no stream to set position"); } ARGF_FORWARD(1, &offset); return rb_io_set_pos(ARGF.current_file, offset); }
将给定的对象写入流;返回 nil
。如果它不是 nil
,则追加输出记录分隔符 $OUTPUT_RECORD_SEPARATOR
($\
)。参见 行 IO.
给定参数 objects
,对于每个对象
-
如果它不是字符串,则通过其方法
to_s
进行转换。 -
写入流。
-
如果不是最后一个对象,则写入输出字段分隔符
$OUTPUT_FIELD_SEPARATOR
($,
),如果它不是nil
。
使用默认分隔符
f = File.open('t.tmp', 'w+') objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero'] p $OUTPUT_RECORD_SEPARATOR p $OUTPUT_FIELD_SEPARATOR f.print(*objects) f.rewind p f.read f.close
输出
nil nil "00.00/10+0izerozero"
使用指定的分隔符
$\ = "\n" $, = ',' f.rewind f.print(*objects) f.rewind p f.read
输出
"0,0.0,0/1,0+0i,zero,zero\n"
如果没有给出参数,则写入 $_
的内容(通常是最新的用户输入)
f = File.open('t.tmp', 'w+') gets # Sets $_ to the most recent user input. f.print f.close
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; } if (argc > 1 && !NIL_P(rb_output_fs)) { rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value"); } 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; }
格式化并将 objects
写入流。
有关 format_string
的详细信息,请参见 格式规范.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE out) { rb_io_write(out, rb_f_sprintf(argc, argv)); return Qnil; }
将字符写入流。参见 字符 IO.
如果 object
是数字,则根据需要转换为整数,然后写入代码为最低有效字节的字符;如果 object
是字符串,则写入第一个字符
$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; }
将给定的objects
写入流中,该流必须处于写入状态;返回nil
。\ 在每个不以换行符结尾的对象之后写入一个换行符。如果在没有参数的情况下调用,则写入一个换行符。参见 行IO。
注意,每个添加的换行符都是字符"\n"<//tt>,而不是输出记录分隔符(<tt>$\
)。
每个对象的处理方式
-
字符串:写入字符串。
-
既不是字符串也不是数组:写入
object.to_s
。 -
数组:写入数组的每个元素;数组可以嵌套。
为了使这些示例简短,我们定义了这个辅助方法
def show(*objects) # Puts objects to file. f = File.new('t.tmp', 'w+') f.puts(objects) # Return file content. f.rewind p f.read f.close end # Strings without newlines. show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n" # Strings, some with newlines. show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n" # Neither strings nor arrays: show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero) # => "0\n0.0\n0/1\n9+0i\nzero\n" # Array of strings. show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n" # Nested arrays. show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE out) { VALUE line, args[2]; /* if no argument given, print newline. */ if (argc == 0) { rb_io_write(out, rb_default_rs); return Qnil; } for (int i = 0; i < argc; i++) { // Convert the argument to a string: if (RB_TYPE_P(argv[i], T_STRING)) { line = argv[i]; } else if (rb_exec_recursive(io_puts_ary, argv[i], out)) { continue; } else { line = rb_obj_as_string(argv[i]); } // Write the line: int n = 0; if (RSTRING_LEN(line) == 0) { args[n++] = rb_default_rs; } else { args[n++] = line; if (!rb_str_end_with_asciichar(line, '\n')) { args[n++] = rb_default_rs; } } rb_io_writev(out, n, args); } return Qnil; }
从 ARGF
中读取length字节。命令行上命名的文件被连接起来,并被此方法视为单个文件,因此在没有参数的情况下调用时,此伪文件的全部内容将被返回。
length必须是非负整数或nil
。
如果length是正整数,read
尝试读取length字节,不进行任何转换(二进制模式)。如果在读取任何内容之前遇到 EOF,则返回nil
。如果在读取过程中遇到 EOF,则返回少于length字节。在整数length的情况下,结果字符串始终使用 ASCII-8BIT 编码。
如果省略length或为nil
,则读取直到 EOF,并应用编码转换(如果适用)。即使在读取任何数据之前遇到 EOF,也会返回一个字符串。
如果length为零,则返回一个空字符串(""
)。
如果存在可选的outbuf参数,则它必须引用一个 String
,该字符串将接收数据。即使在方法调用之前outbuf不为空,它也只包含接收到的数据。
例如
$ echo "small" > small.txt $ echo "large" > large.txt $ ./glark.rb small.txt large.txt ARGF.read #=> "small\nlarge" ARGF.read(200) #=> "small\nlarge" ARGF.read(2) #=> "sm" ARGF.read(0) #=> ""
注意,此方法的行为类似于 C 中的 fread() 函数。这意味着它会重试调用 read(2) 系统调用以使用指定的长度读取数据。如果您需要类似于单个 read(2) 系统调用的行为,请考虑使用 ARGF#readpartial
或 ARGF#read_nonblock
。
static VALUE argf_read(int argc, VALUE *argv, VALUE argf) { VALUE tmp, str, length; long len = 0; rb_scan_args(argc, argv, "02", &length, &str); if (!NIL_P(length)) { len = NUM2LONG(argv[0]); } if (!NIL_P(str)) { StringValue(str); rb_str_resize(str,0); argv[1] = Qnil; } retry: if (!next_argv()) { return str; } if (ARGF_GENERIC_INPUT_P()) { tmp = argf_forward(argc, argv, argf); } else { tmp = io_read(argc, argv, ARGF.current_file); } if (NIL_P(str)) str = tmp; else if (!NIL_P(tmp)) rb_str_append(str, tmp); if (NIL_P(tmp) || NIL_P(length)) { if (ARGF.next_p != -1) { argf_close(argf); ARGF.next_p = 1; goto retry; } } else if (argc >= 1) { long slen = RSTRING_LEN(str); if (slen < len) { argv[0] = LONG2NUM(len - slen); goto retry; } } return str; }
以非阻塞模式从 ARGF
流中读取最多maxlen字节。
static VALUE argf_read_nonblock(int argc, VALUE *argv, VALUE argf) { VALUE opts; rb_scan_args(argc, argv, "11:", NULL, NULL, &opts); if (!NIL_P(opts)) argc--; return argf_getpartial(argc, argv, argf, opts, 1); }
从 ARGF
中读取下一个 8 位字节,并将其作为 Integer
返回。在读取最后一个文件的最后一个字节后,引发 EOFError
。
例如
$ echo "foo" > file $ ruby argf.rb file ARGF.readbyte #=> 102 ARGF.readbyte #=> 111 ARGF.readbyte #=> 111 ARGF.readbyte #=> 10 ARGF.readbyte #=> end of file reached (EOFError)
static VALUE argf_readbyte(VALUE argf) { VALUE c; NEXT_ARGF_FORWARD(0, 0); c = argf_getbyte(argf); if (NIL_P(c)) { rb_eof_error(); } return c; }
从 ARGF
中读取下一个字符,并将其作为 String
返回。在读取完最后一个文件的最后一个字符后,会引发 EOFError
。
例如
$ echo "foo" > file $ ruby argf.rb file ARGF.readchar #=> "f" ARGF.readchar #=> "o" ARGF.readchar #=> "o" ARGF.readchar #=> "\n" ARGF.readchar #=> end of file reached (EOFError)
static VALUE argf_readchar(VALUE argf) { VALUE ch; retry: if (!next_argv()) rb_eof_error(); if (!RB_TYPE_P(ARGF.current_file, T_FILE)) { ch = forward_current(rb_intern("getc"), 0, 0); } else { ch = rb_io_getc(ARGF.current_file); } if (NIL_P(ch) && ARGF.next_p != -1) { argf_close(argf); ARGF.next_p = 1; goto retry; } return ch; }
从当前文件中的 ARGF
返回下一行。
默认情况下,假设行以 $/
分隔;要使用其他字符作为分隔符,请将其作为 String
提供给 sep 参数。
可选的 limit 参数指定要返回的每行的字符数。默认情况下,返回所有字符。
在文件末尾会引发 EOFError
。
static VALUE argf_readline(int argc, VALUE *argv, VALUE argf) { VALUE line; if (!next_argv()) rb_eof_error(); ARGF_FORWARD(argc, argv); line = argf_gets(argc, argv, argf); if (NIL_P(line)) { rb_eof_error(); } return line; }
完整读取 ARGF
中的每个文件,返回一个包含文件行内容的 Array
。假设行之间用 sep 分隔。
lines = ARGF.readlines lines[0] #=> "This is line one\n"
有关所有选项的完整描述,请参阅 IO.readlines
。
static VALUE argf_readlines(int argc, VALUE *argv, VALUE argf) { long lineno = ARGF.lineno; VALUE lines, ary; ary = rb_ary_new(); while (next_argv()) { if (ARGF_GENERIC_INPUT_P()) { lines = forward_current(rb_intern("readlines"), argc, argv); } else { lines = rb_io_readlines(argc, argv, ARGF.current_file); argf_close(argf); } ARGF.next_p = 1; rb_ary_concat(ary, lines); ARGF.lineno = lineno + RARRAY_LEN(ary); ARGF.last_lineno = ARGF.lineno; } ARGF.init_p = 0; return ary; }
从 ARGF
流中读取最多 maxlen 字节。
如果存在可选的outbuf参数,则它必须引用一个 String
,该字符串将接收数据。即使在方法调用之前outbuf不为空,它也只包含接收到的数据。
在 ARGF
流结束时引发 EOFError
。由于 ARGF
流是多个文件的串联,内部在每个文件末尾都会发生 EOF。 ARGF.readpartial
会为除最后一个 EOF 之外的所有 EOF 返回空字符串,并为最后一个 EOF 引发 EOFError
。
static VALUE argf_readpartial(int argc, VALUE *argv, VALUE argf) { return argf_getpartial(argc, argv, argf, Qnil, 0); }
将当前文件定位到输入开头,并将 ARGF.lineno
重置为零。
ARGF.readline #=> "This is line one\n" ARGF.rewind #=> 0 ARGF.lineno #=> 0 ARGF.readline #=> "This is line one\n"
static VALUE argf_rewind(VALUE argf) { VALUE ret; int old_lineno; if (!next_argv()) { rb_raise(rb_eArgError, "no stream to rewind"); } ARGF_FORWARD(0, 0); old_lineno = RFILE(ARGF.current_file)->fptr->lineno; ret = rb_io_rewind(ARGF.current_file); if (!global_argf_p(argf)) { ARGF.last_lineno = ARGF.lineno -= old_lineno; } return ret; }
如果只指定一个参数,则从 ARGF
读取的字符串将被标记为指定的编码。
如果给出用冒号分隔的两个编码名称,例如“ascii:utf-8”,则读取的字符串将从第一个编码(外部编码)转换为第二个编码(内部编码),然后标记为第二个编码。
如果指定了两个参数,则它们必须是编码对象或编码名称。同样,第一个指定外部编码;第二个指定内部编码。
如果指定了外部编码和内部编码,则可选的 Hash
参数可用于调整转换过程。此哈希的结构在 String#encode
文档中解释。
例如
ARGF.set_encoding('ascii') # Tag the input as US-ASCII text ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII # to UTF-8.
static VALUE argf_set_encoding(int argc, VALUE *argv, VALUE argf) { rb_io_t *fptr; if (!next_argv()) { rb_raise(rb_eArgError, "no stream to set encoding"); } rb_io_set_encoding(argc, argv, ARGF.current_file); GetOpenFile(ARGF.current_file, fptr); ARGF.encs = fptr->encs; return argf; }
将当前文件设置为 ARGV 中的下一个文件。如果没有更多文件,则没有效果。
例如
$ ruby argf.rb foo bar ARGF.filename #=> "foo" ARGF.skip ARGF.filename #=> "bar"
static VALUE argf_skip(VALUE argf) { if (ARGF.init_p && ARGF.next_p == 0) { argf_close(argf); ARGF.next_p = 1; } return argf; }
返回 ARGF
中当前文件的当前偏移量(以字节为单位)。
ARGF.pos #=> 0 ARGF.gets #=> "This is line one\n" ARGF.pos #=> 17
static VALUE argf_tell(VALUE argf) { if (!next_argv()) { rb_raise(rb_eArgError, "no stream to tell"); } ARGF_FORWARD(0, 0); return rb_io_tell(ARGF.current_file); }
完整读取 ARGF
中的每个文件,返回一个包含文件行内容的 Array
。假设行之间用 sep 分隔。
lines = ARGF.readlines lines[0] #=> "This is line one\n"
有关所有选项的完整描述,请参阅 IO.readlines
。
返回“ARGF”。
static VALUE argf_to_s(VALUE argf) { return rb_str_new2("ARGF"); }
如果启用了就地模式,则返回与 ARGF 绑定的用于写入的 IO
实例。
static VALUE argf_write_io(VALUE argf) { if (!RTEST(ARGF.current_file)) { rb_raise(rb_eIOError, "not opened for writing"); } return GetWriteIO(ARGF.current_file); }
如果就地模式,则写入 string。
static VALUE argf_write(VALUE argf, VALUE str) { return rb_io_write(argf_write_io(argf), str); }