класс ARGF
ARGF и ARGV
Объект ARGF работает с массивом в глобальной переменной ARGV, чтобы сделать $stdin и файловые потоки доступными в программе Ruby:
-
ARGV можно рассматривать как массив вектора аргументов.
Изначально он содержит аргументы командной строки и параметры, переданные программе Ruby; программа может изменять этот массив по своему усмотрению.
-
ARGF можно рассматривать как объект файлов аргументов.
Он может обращаться к файловым потокам и/или потоку
$stdin, исходя из содержимогоARGV. Это позволяет удобно задавать в командной строке потоки для чтения программой Ruby.
Чтение
ARGF может читать из потоков источников, которые в каждый конкретный момент определяются содержимым ARGV.
Самый простой случай
Если первое в истории чтение ARGF выполняется при пустом ARGV ([]), источником служит $stdin:
-
Файл
t.rb:p ['ARGV', ARGV] p ['ARGF.read', ARGF.read]
-
Команды и вывод (содержимое файлов
foo.txtиbar.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.txt и bar.txt:
$ cat foo.txt Foo 0 Foo 1 $ cat bar.txt Bar 0 Bar 1 Bar 2 Bar 3
Источники в ARGV
При любом чтении ARGF, кроме самого простого случая (то есть кроме первого в истории чтения ARGF при пустом ARGV), источники определяются содержимым ARGV.
ARGF предполагает, что каждый элемент массива ARGV является потенциальным источником и представляет собой одно из следующего:
-
Строковый путь к файлу, который можно открыть как поток.
-
Символ
'-', обозначающий поток$stdin.
Каждый элемент, который не является одним из этих вариантов, следует удалить из ARGV до того, как ARGF обратится к этому источнику.
В следующем примере:
-
Пути к файлам
foo.txtиbar.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 "Read: #{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"]
Указание $stdin в ARGV
Чтобы указать поток $stdin в ARGV, используйте символ '-':
-
Файл
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 игнорируется (исключение: см. Указание $stdin в ARGV):
-
Команда и вывод:
$ 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 предоставляют иные способы доступа к этому содержимому, в том числе:
-
Доступ к кодовым точкам:
each_codepoint. -
Доступ к источникам:
read,read_nonblock,readpartial.
О модуле 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.
Методы, относящиеся к режиму записи на месте:
Методы записи:
Общедоступные методы экземпляра
static VALUE
argf_argv(VALUE argf)
{
return ARGF.argv;
} Возвращает массив ARGV, содержащий аргументы, переданные вашему скрипту, по одному в каждом элементе.
Например:
$ ruby argf.rb -v glark.txt ARGF.argv #=> ["-v", "glark.txt"]
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;
} static VALUE
argf_binmode_p(VALUE argf)
{
return RBOOL(ARGF.binmode);
} Возвращает true, если чтение ARGF выполняется в двоичном режиме; в противном случае — false. Чтобы включить двоичный режим, используйте ARGF.binmode.
Например:
ARGF.binmode? #=> false ARGF.binmode ARGF.binmode? #=> true
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;
} Закрывает текущий файл и переходит к следующему файлу в ARGV. Если файлов для открытия больше нет, просто закрывает текущий файл. STDIN не закрывается.
Например:
$ ruby argf.rb foo bar ARGF.filename #=> "foo" ARGF.close ARGF.filename #=> "bar" ARGF.close
static VALUE
argf_closed(VALUE argf)
{
next_argv();
ARGF_FORWARD(0, 0);
return rb_io_closed_p(ARGF.current_file);
} Возвращает true, если текущий файл закрыт; в противном случае — false. Чтобы действительно закрыть текущий файл, используйте ARGF.close.
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;
} Возвращает перечислитель, который перебирает каждую строку (разделённую sep, который по умолчанию равен символу новой строки вашей платформы) каждого файла в ARGV. Если передан блок, каждая строка по очереди передаётся ему; в противном случае возвращается перечислитель. Необязательный аргумент 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_byte(VALUE argf)
{
RETURN_ENUMERATOR(argf, 0, 0);
FOREACH_ARGF() {
argf_block_call(rb_intern("each_byte"), 0, 0, argf);
}
return argf;
} Перебирает каждый байт каждого файла в ARGV. Байт возвращается как Integer в диапазоне 0..255.
Этот метод позволяет работать с файлами, указанными в командной строке, как с одним файлом, состоящим из объединённого содержимого всех файлов с указанными именами. После возврата последнего байта первого файла возвращается первый байт второго файла. Метод ARGF.filename позволяет определить имя файла для текущего байта.
Если блок не передан, вместо этого возвращается перечислитель.
Например:
ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
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;
} Перебирает каждую кодовую точку каждого файла в ARGF.
Этот метод позволяет работать с файлами, указанными в командной строке, как с одним файлом, состоящим из объединённого содержимого всех файлов с указанными именами. После возврата последней кодовой точки первого файла возвращается первая кодовая точка второго файла. Метод ARGF.filename позволяет определить имя файла, в котором находится текущая кодовая точка.
Если блок не передан, вместо этого возвращается перечислитель.
Возвращает перечислитель, который перебирает каждую строку (разделённую sep, который по умолчанию равен символу новой строки вашей платформы) каждого файла в ARGV. Если передан блок, каждая строка по очереди передаётся ему; в противном случае возвращается перечислитель. Необязательный аргумент 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_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;
} Возвращает true, если текущий файл в ARGF находится в конце файла, то есть данных для чтения больше нет. Поток должен быть открыт для чтения, иначе будет вызвано исключение IOError.
$ echo "eof" | ruby argf.rb
ARGF.eof? #=> false
3.times { ARGF.readchar }
ARGF.eof? #=> false
ARGF.readchar #=> "\n"
ARGF.eof? #=> true Возвращает true, если текущий файл в ARGF находится в конце файла, то есть данных для чтения больше нет. Поток должен быть открыт для чтения, иначе будет вызвано исключение 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_external_encoding(VALUE argf)
{
return argf_encoding(argf, rb_io_external_encoding);
} Возвращает внешнюю кодировку файлов, читаемых из ARGF, в виде объекта Encoding. Внешняя кодировка — это кодировка текста, в которой он хранится в файле. В отличие от неё, ARGF.internal_encoding — это кодировка, используемая для представления этого текста в Ruby.
Чтобы задать внешнюю кодировку, используйте ARGF.set_encoding.
Например:
ARGF.external_encoding #=> #<Encoding:UTF-8>
static VALUE
argf_file(VALUE argf)
{
next_argv();
return ARGF.current_file;
} static VALUE
argf_filename(VALUE argf)
{
next_argv();
return ARGF.filename;
} Возвращает имя текущего файла. Если текущим файлом является 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_fileno(VALUE argf)
{
if (!next_argv()) {
rb_raise(rb_eArgError, "no stream");
}
ARGF_FORWARD(0, 0);
return rb_io_fileno(ARGF.current_file);
} Возвращает целое число, представляющее числовой файловый дескриптор текущего файла. Если текущего файла нет, вызывает исключение ArgumentError.
ARGF.fileno #=> 3
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;
} Считывает следующий 8-битный байт (0..255) из ARGF. Возвращает 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_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. В конце потока возвращает 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_gets(int argc, VALUE *argv, VALUE argf)
{
VALUE line;
line = argf_getline(argc, argv, argf);
rb_lastline_set(line);
return line;
} Возвращает следующую строку из текущего файла в ARGF.
По умолчанию строки считаются разделёнными символом $/; чтобы использовать другой символ в качестве разделителя, передайте его как String в аргументе sep.
Необязательный аргумент limit задаёт количество символов, возвращаемых из каждой строки. По умолчанию возвращаются все символы.
Подробную информацию об аргументе getline_args см. в разделе IO.readlines.
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);
} Возвращает расширение файла, добавляемое к именам резервных копий изменённых файлов при редактировании на месте. Это значение можно задать с помощью ARGF.inplace_mode= или передав переключатель -i двоичному файлу Ruby.
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;
} Задаёт расширение имени файла для режима редактирования на месте, используя переданное значение 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_internal_encoding(VALUE argf)
{
return argf_encoding(argf, rb_io_internal_encoding);
} Возвращает внутреннюю кодировку строк, считываемых из ARGF, в виде объекта Encoding.
Если ARGF.set_encoding был вызван с двумя именами кодировок, возвращается второе. В противном случае, если задано Encoding.default_external, возвращается это значение. Если ни одно из условий не выполнено, используется внешняя кодировка по умолчанию, указанная в командной строке. Если кодировка неизвестна, возвращается nil.
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
static VALUE
argf_set_lineno(VALUE argf, VALUE val)
{
ARGF.lineno = NUM2INT(val);
ARGF.last_lineno = ARGF.lineno;
return val;
} Задаёт номер строки 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
Возвращает имя текущего файла. Если текущим файлом является 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
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);
} Переходит к позиции position (в байтах) в ARGF.
Например:
ARGF.pos = 17 ARGF.gets #=> "This is line two\n"
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;
} Записывает переданные объекты в поток; возвращает nil. Добавляет разделитель записей вывода $OUTPUT_RECORD_SEPARATOR ($\), если он не равен nil. См. раздел Построчный ввод-вывод.
Если передан аргумент 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_printf(int argc, const VALUE *argv, VALUE out)
{
rb_io_write(out, rb_f_sprintf(argc, argv));
return Qnil;
} Форматирует и записывает objects в поток.
Подробную информацию о format_string см. в разделе Спецификации формата.
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;
} Записывает символ в поток. См. раздел Посимвольный ввод-вывод.
Если object является числом, при необходимости преобразует его в целое число, а затем записывает символ, код которого равен младшему байту; если object является строкой, записывает первый символ:
$stdout.putc "A" $stdout.putc 65
Вывод:
AA
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;
} Записывает переданные objects в поток, который должен быть открыт для записи; возвращает nil.\ После каждого объекта, который ещё не заканчивается последовательностью символов новой строки, записывает символ новой строки. Если вызван без аргументов, записывает символ новой строки. См. раздел Построчный ввод-вывод.
Обратите внимание, что каждый добавляемый символ новой строки — это символ "\n"<//tt>, not the output record separator (<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"
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;
} Считывает length байт из ARGF. Файлы, указанные в командной строке, объединяются и рассматриваются этим методом как один файл, поэтому при вызове без аргументов он возвращает содержимое этого псевдофайла целиком.
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) #=> ""
Обратите внимание, что этот метод работает подобно функции fread() в C. Это означает, что он повторно вызывает системные вызовы read(2), чтобы считать данные заданной длины. Если требуется поведение, аналогичное одному системному вызову read(2), рассмотрите возможность использовать ARGF#readpartial или ARGF#read_nonblock.
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);
} Читает не более maxlen байт из потока ARGF в неблокирующем режиме.
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;
} Читает следующий 8-битный байт из ARGF и возвращает его как 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_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. После чтения последнего символа последнего файла вызывает 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_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.
По умолчанию строки считаются разделёнными символом $/; чтобы использовать другой символ в качестве разделителя, укажите его как String для аргумента sep.
Необязательный аргумент limit задаёт количество символов в каждой возвращаемой строке. По умолчанию возвращаются все символы.
В конце файла вызывается EOFError.
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 и возвращает Array, содержащий строки из этих файлов. Предполагается, что строки разделены символом sep.
lines = ARGF.readlines lines[0] #=> "This is line one\n"
Полное описание всех параметров см. в IO.readlines.
static VALUE
argf_readpartial(int argc, VALUE *argv, VALUE argf)
{
return argf_getpartial(argc, argv, argf, Qnil, 0);
} Читает не более maxlen байт из потока ARGF.
Если указан необязательный аргумент outbuf, он должен ссылаться на String, в которую будут записаны данные. После вызова метода outbuf будет содержать только полученные данные, даже если изначально она была непустой.
В конце потока ARGF вызывается EOFError. Поскольку поток ARGF представляет собой конкатенацию нескольких файлов, фактически EOF возникает для каждого файла. ARGF.readpartial возвращает пустые строки при EOF для всех файлов, кроме последнего, а при EOF последнего файла вызывает EOFError.
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.lineno в ноль.
ARGF.readline #=> "This is line one\n" ARGF.rewind #=> 0 ARGF.lineno #=> 0 ARGF.readline #=> "This is line one\n"
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);
} 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;
} Если указан один аргумент, строкам, читаемым из 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_skip(VALUE argf)
{
if (ARGF.init_p && ARGF.next_p == 0) {
argf_close(argf);
ARGF.next_p = 1;
}
return argf;
} Переключает текущий файл на следующий файл в ARGV. Если файлов больше нет, метод ничего не делает.
Например:
$ ruby argf.rb foo bar ARGF.filename #=> "foo" ARGF.skip ARGF.filename #=> "bar"
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.
ARGF.pos #=> 0 ARGF.gets #=> "This is line one\n" ARGF.pos #=> 17
Полностью читает каждый файл из ARGF и возвращает Array, содержащий строки из этих файлов. Предполагается, что строки разделены символом sep.
lines = ARGF.readlines lines[0] #=> "This is line one\n"
Полное описание всех параметров см. в IO.readlines.
Возвращает целое число, представляющее числовой файловый дескриптор текущего файла. Если текущего файла нет, вызывает ArgumentError.
ARGF.fileno #=> 3
static VALUE
argf_to_io(VALUE argf)
{
next_argv();
ARGF_FORWARD(0, 0);
return ARGF.current_file;
} static VALUE
argf_to_s(VALUE argf)
{
return rb_str_new2("ARGF");
} Возвращает «ARGF».
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);
} Если включён режим inplace, возвращает экземпляр IO, связанный с ARGF для записи.
static VALUE
argf_write(int argc, VALUE *argv, VALUE argf)
{
return rb_io_writev(argf_write_io(argf), argc, argv);
} Записывает каждый из переданных objects, если включён режим inplace.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.