class ARGF

ARGF 和 ARGV

ARGF 对象与全局变量 ARGV 中的数组一起工作,使 $stdin 和文件流在 Ruby 程序中可用

  • ARGV 可以被认为是参数向量数组。

    最初,它包含传递给 Ruby 程序的命令行参数和选项;程序可以根据需要修改该数组。

  • ARGF 可以被认为是参数文件对象。

    它可以根据在 ARGV 中找到的内容访问文件流和/或 $stdin 流。这为命令行提供了一种方便的方式来指定 Ruby 程序要读取的流。

读取

ARGF 可以从流中读取,这些源流在任何特定时间都由 ARGV 的内容决定。

最简单的情况

当使用空的 ARGV ([]) 进行第一次 ARGF 读取时,源是 $stdin

  • 文件 t.rb

    p ['ARGV', ARGV]
    p ['ARGF.read', ARGF.read]
    
  • 命令和输出(有关文件 foo.txtbar.txt 的内容,请参见下文)

    $ echo "Open the pod bay doors, Hal." | ruby t.rb
    ["ARGV", []]
    ["ARGF.read", "Open the pod bay doors, Hal.\n"]
    
    $ cat foo.txt bar.txt | ruby t.rb
    ["ARGV", []]
    ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]

关于示例

这里的许多示例都假设存在文件 foo.txtbar.txt

$ cat foo.txt
Foo 0
Foo 1
$ cat bar.txt
Bar 0
Bar 1
Bar 2
Bar 3

ARGV 中的源

对于任何 ARGF 读取,除了 最简单的情况(即,除了 使用空的 ARGV 进行的第一次 ARGF 读取),源都在 ARGV 中找到。

ARGF 假设数组 ARGV 中的每个元素都是一个潜在的源,并且是以下之一

  • 可以作为流打开的文件的字符串路径。

  • 字符 '-',表示流 $stdin

在 ARGF 访问该源之前,应从 ARGV 中删除不是这些之一的每个元素。

在以下示例中

  • 文件路径 foo.txtbar.txt 可以保留为潜在的源。

  • 应删除选项 --xyzzy--mojo

示例

  • 文件 t.rb

    # Print arguments (and options, if any) found on command line.
    p ['ARGV', ARGV]
    
  • 命令和输出

    $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
    ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]

ARGF 的流访问从左到右考虑 ARGV 的元素

  • 文件 t.rb

    p "ARGV: #{ARGV}"
    p "Line: #{ARGF.read}" # Read everything from all specified streams.
    
  • 命令和输出

    $ ruby t.rb foo.txt bar.txt
    "ARGV: [\"foo.txt\", \"bar.txt\"]"
    "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"

因为 ARGV 的值是一个普通数组,所以您可以操纵它来控制 ARGF 考虑哪些源

  • 如果从 ARGV 中删除一个元素,ARGF 将不会考虑相应的源。

  • 如果向 ARGV 添加一个元素,ARGF 将考虑相应的源。

当访问其对应的源时,将删除 ARGV 中的每个元素;当所有源都被访问后,该数组为空

  • 文件 t.rb

    until ARGV.empty? && ARGF.eof?
      p "ARGV: #{ARGV}"
      p "Line: #{ARGF.readline}" # Read each line from each specified stream.
    end
    
  • 命令和输出

    $ ruby t.rb foo.txt bar.txt
    "ARGV: [\"foo.txt\", \"bar.txt\"]"
    "Line: Foo 0\n"
    "ARGV: [\"bar.txt\"]"
    "Line: Foo 1\n"
    "ARGV: [\"bar.txt\"]"
    "Line: Bar 0\n"
    "ARGV: []"
    "Line: Bar 1\n"
    "ARGV: []"
    "Line: Bar 2\n"
    "ARGV: []"
    "Line: Bar 3\n"

ARGV 中的文件路径

ARGV 数组可能包含指定 ARGF 读取源的文件路径。

此程序打印它从命令行上指定路径的文件中读取的内容

  • 文件 t.rb

    p ['ARGV', ARGV]
    # Read and print all content from the specified sources.
    p ['ARGF.read', ARGF.read]
    
  • 命令和输出

    $ ruby t.rb foo.txt bar.txt
    ["ARGV", [foo.txt, bar.txt]
    ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]

ARGV 中指定 $stdin

要在 ARGV 中指定流 $stdin,请使用字符 '-'

  • 文件 t.rb

    p ['ARGV', ARGV]
    p ['ARGF.read', ARGF.read]
    
  • 命令和输出

    $ echo "Open the pod bay doors, Hal." | ruby t.rb -
    ["ARGV", ["-"]]
    ["ARGF.read", "Open the pod bay doors, Hal.\n"]

当没有给出字符 '-' 时,将忽略流 $stdin(例外:请参阅 在 ARGV 中指定 $stdin

  • 命令和输出

    $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
    "ARGV: [\"foo.txt\", \"bar.txt\"]"
    "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"

ARGV 中的混合和重复

对于 ARGF 读取器,ARGV 可能包含文件路径和字符 '-' 的任何混合,包括重复项。

ARGV 的修改

正在运行的 Ruby 程序可以对 ARGV 数组进行任何修改;ARGV 的当前值会影响 ARGF 读取。

空的 ARGV

对于空的 ARGV,ARGF 读取方法要么返回 nil,要么引发异常,具体取决于特定方法。

更多读取方法

如上所述,方法 ARGF#read 将所有源的内容读取到单个字符串中。其他 ARGF 方法提供了其他访问该内容的方式;这些方法包括

关于 Enumerable

ARGF 包含模块 Enumerable。Enumerable 中的几乎所有方法都调用包含类中的方法 #each

请注意:在 ARGF 中,方法 each 返回来自的数据,而不是来自 ARGV 的数据;因此,例如,ARGF#entries 返回来自源的行数组,而不是来自 ARGV 的字符串数组

  • 文件 t.rb

    p ['ARGV', ARGV]
    p ['ARGF.entries', ARGF.entries]
    
  • 命令和输出

    $ ruby t.rb foo.txt bar.txt
    ["ARGV", ["foo.txt", "bar.txt"]]
    ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]

写入

如果原地模式生效,ARGF 可以写入目标流,这些目标流在任何特定时间都由 ARGV 的内容确定。

关于原地模式的方法

用于写入的方法

公共实例方法

argv → ARGV 单击以切换源

返回 ARGV 数组,其中包含传递给你的脚本的参数,每个元素一个参数。

例如

$ ruby argf.rb -v glark.txt

ARGF.argv   #=> ["-v", "glark.txt"]
static VALUE
argf_argv(VALUE argf)
{
    return ARGF.argv;
}
binmode → ARGF 单击以切换源

ARGF 置于二进制模式。一旦流处于二进制模式,就无法将其重置为非二进制模式。此选项具有以下影响

  • 禁用换行符转换。

  • 禁用 Encoding 转换。

  • 内容被视为 ASCII-8BIT。

static VALUE
argf_binmode_m(VALUE argf)
{
    ARGF.binmode = 1;
    next_argv();
    ARGF_FORWARD(0, 0);
    rb_io_ascii8bit_binmode(ARGF.current_file);
    return argf;
}
binmode? → true or false 单击以切换源

如果 ARGF 以二进制模式读取,则返回 true;否则返回 false。要启用二进制模式,请使用 ARGF.binmode

例如

ARGF.binmode?  #=> false
ARGF.binmode
ARGF.binmode?  #=> true
static VALUE
argf_binmode_p(VALUE argf)
{
    return RBOOL(ARGF.binmode);
}
close → ARGF 单击以切换源

关闭当前文件并跳到 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;
}
closed? → true or false 单击以切换源

如果当前文件已关闭,则返回 true;否则返回 false。使用 ARGF.close 实际关闭当前文件。

static VALUE
argf_closed(VALUE argf)
{
    next_argv();
    ARGF_FORWARD(0, 0);
    return rb_io_closed_p(ARGF.current_file);
}
each(sep=$/) {|line| block } → ARGF 单击以切换源
each(sep=$/, limit) {|line| block } → ARGF
each(...) → an_enumerator

返回一个枚举器,该枚举器迭代 ARGV 中每个文件的每一行(由 sep 分隔,默认为你的平台的换行符)。如果提供了块,则将依次将每行产生到块中,否则将返回一个枚举器。可选的 limit 参数是一个 Integer,指定每行的最大长度;较长的行将根据此限制进行拆分。

此方法允许你将命令行上提供的文件视为由每个命名文件的串联组成的单个文件。在返回第一个文件的最后一行后,将返回第二个文件的第一行。可以使用 ARGF.filenameARGF.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;
}
别名也为:each_line
each_byte {|byte| block } → ARGF 单击以切换源
each_byte → an_enumerator

迭代 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;
}
each_char {|char| block } → ARGF 单击以切换源
each_char → an_enumerator

迭代 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;
}
each_codepoint {|codepoint| block } → ARGF 点击以切换源代码
each_codepoint → an_enumerator

迭代 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;
}
each_line(*args)

返回一个枚举器,该枚举器迭代 ARGV 中每个文件的每一行(由 sep 分隔,默认为你的平台的换行符)。如果提供了块,则将依次将每行产生到块中,否则将返回一个枚举器。可选的 limit 参数是一个 Integer,指定每行的最大长度;较长的行将根据此限制进行拆分。

此方法允许你将命令行上提供的文件视为由每个命名文件的串联组成的单个文件。在返回第一个文件的最后一行后,将返回第二个文件的第一行。可以使用 ARGF.filenameARGF.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
别名:each
eof → true 或 false 点击以切换源代码

如果 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;
}
也别名为:eof?
eof?()

如果 ARGF 中的当前文件已到达文件末尾,即没有数据可读,则返回 true。该流必须以读取模式打开,否则会引发 IOError

$ echo "eof" | ruby argf.rb

ARGF.eof?                 #=> false
3.times { ARGF.readchar }
ARGF.eof?                 #=> false
ARGF.readchar             #=> "\n"
ARGF.eof?                 #=> true
别名:eof
external_encoding → encoding 点击以切换源代码

返回从 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);
}
file → IO 或 File 对象 点击以切换源代码

将当前文件作为 IOFile 对象返回。当当前文件为 STDIN 时,返回 $stdin

例如

$ echo "foo" > foo
$ echo "bar" > bar

$ ruby argf.rb foo bar

ARGF.file      #=> #<File:foo>
ARGF.read(5)   #=> "foo\nb"
ARGF.file      #=> #<File:bar>
static VALUE
argf_file(VALUE argf)
{
    next_argv();
    return ARGF.current_file;
}
filename → String 点击以切换源代码

返回当前文件名。当当前文件为 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;
}
也别名为:path
fileno → integer 点击以切换源代码

返回表示当前文件的数字文件描述符的整数。如果当前没有文件,则引发 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);
}
也别名为:to_i
getbyte → Integer 或 nil 点击以切换源代码

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;
}
getc → String 或 nil 点击以切换源代码

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;
}
gets(sep=$/ [, getline_args]) → string 或 nil 点击以切换源代码
gets(limit [, getline_args]) → string 或 nil
gets(sep, limit [, getline_args]) → string 或 nil

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;
}
inplace_mode → String 点击以切换源代码

返回在就地编辑模式下,附加到修改文件的备份副本名称的文件扩展名。可以使用 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);
}
inplace_mode = ext → ARGF 点击以切换源代码

将就地编辑模式的文件扩展名设置为给定的 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;
}
inspect()

返回 “ARGF”。

别名:to_s
internal_encoding → encoding 点击以切换源代码

返回从 ARGF 读取的字符串的内部编码,表示为一个 Encoding 对象。

如果已使用两个编码名称调用 ARGF.set_encoding,则返回第二个名称。否则,如果已设置 Encoding.default_external,则返回该值。如果命令行中指定了默认的外部编码,则使用该值。如果编码未知,则返回 nil

static VALUE
argf_internal_encoding(VALUE argf)
{
    return argf_encoding(argf, rb_io_internal_encoding);
}
lineno → integer 点击以切换源代码

返回 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);
}
lineno = integer → integer 点击以切换源代码

ARGF 的整体行号设置为给定的 Integer

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;
}
path → String

返回当前文件名。当当前文件为 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"
别名:filename
pos → Integer

返回 ARGF 中当前文件的当前偏移量(以字节为单位)。

ARGF.pos    #=> 0
ARGF.gets   #=> "This is line one\n"
ARGF.pos    #=> 17
别名:tell
pos = position → Integer 点击以切换源代码

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);
}
print(*objects) → nil 点击以切换源代码

将给定的对象写入流;返回 nil。如果输出记录分隔符 $OUTPUT_RECORD_SEPARATOR ($\) 不为 nil,则附加它。请参阅 行 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
printf(format_string, *objects) → nil 点击以切换源代码

格式化并将 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;
}
putc(object) → object 点击以切换源代码

将一个字符写入流。请参阅 字符 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;
}
puts(*objects) → nil 点击以切换源代码

将给定的 objects 写入流,该流必须打开以进行写入;返回 nil。在每个不以换行符序列结尾的对象之后写入换行符。如果没有参数调用,则写入换行符。请参阅 行 IO

请注意,每个添加的换行符都是字符 "\n"<//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;
}
read([length [, outbuf]]) → string, outbuf, 或 nil 点击以切换源代码

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#readpartialARGF#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;
}
read_nonblock(maxlen[, options]) → string 点击以切换源代码
read_nonblock(maxlen, outbuf[, options]) → outbuf

以非阻塞模式从 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);
}
readbyte → Integer 点击以切换源代码

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;
}
readchar → String 或 nil 点击以切换源代码

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;
}
readline(sep=$/) → string 点击以切换源代码
readline(limit) → string
readline(sep, limit) → string

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;
}
readlines(sep = $/, chomp: false) → array 点击以切换源代码
readlines(limit, chomp: false) → array
readlines(sep, limit, chomp: false) → array

读取 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;
}
别名:to_a
readpartial(maxlen) → string 点击以切换源代码
readpartial(maxlen, outbuf) → outbuf

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);
}
rewind → 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;
}
seek(amount, whence=IO::SEEK_SET) → 0 点击以切换源代码

根据 whence 的值,在 ARGF 流中查找偏移量为 amount (一个 Integer)的位置。有关更多详细信息,请参阅 IO#seek

static VALUE
argf_seek_m(int argc, VALUE *argv, VALUE argf)
{
    if (!next_argv()) {
        rb_raise(rb_eArgError, "no stream to seek");
    }
    ARGF_FORWARD(argc, argv);
    return rb_io_seek_m(argc, argv, ARGF.current_file);
}
set_encoding(ext_enc) → ARGF 点击以切换源代码
set_encoding("ext_enc:int_enc") → ARGF
set_encoding(ext_enc, int_enc) → ARGF
set_encoding("ext_enc:int_enc", opt) → ARGF
set_encoding(ext_enc, int_enc, opt) → ARGF

如果指定了单个参数,则从 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;
}
skip → 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;
}
tell → Integer 点击以切换源代码

返回 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);
}
别名:pos
to_a(sep = $/, chomp: false) → array
to_a(limit, chomp: false) → array
to_a(sep, limit, chomp: false) → array

读取 ARGF 中的每个文件的全部内容,并返回一个包含文件行的 Array。行被假定由 sep 分隔。

lines = ARGF.readlines
lines[0]                #=> "This is line one\n"

有关所有选项的完整说明,请参阅 IO.readlines

别名:readlines
to_i → integer

返回表示当前文件的数字文件描述符的整数。如果当前没有文件,则引发 ArgumentError

ARGF.fileno    #=> 3
别名:fileno
to_io → IO 点击以切换源代码

返回一个表示当前文件的 IO 对象。除非当前文件是像 STDIN 这样的流,否则这将是一个 File 对象。

例如

ARGF.to_io    #=> #<File:glark.txt>
ARGF.to_io    #=> #<IO:<STDIN>>
static VALUE
argf_to_io(VALUE argf)
{
    next_argv();
    ARGF_FORWARD(0, 0);
    return ARGF.current_file;
}
to_s → String 点击以切换源代码

返回 “ARGF”。

static VALUE
argf_to_s(VALUE argf)
{
    return rb_str_new2("ARGF");
}
别名:inspect
to_write_io → io 点击以切换源代码

如果启用了原地模式,则返回与 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);
}
write(*objects) → integer 点击以切换源代码

如果处于原地模式,则写入给定的每个 objects

static VALUE
argf_write(int argc, VALUE *argv, VALUE argf)
{
    return rb_io_writev(argf_write_io(argf), argc, argv);
}