Spec-Zone.ru › Ruby 3.2

класс IO

Родитель:
Объект
Включенные модули:
File::Constants, Enumerable

Экземпляр класса IO (обычно называемый потоком) представляет собой поток ввода/вывода в базовой операционной системе. Класс IO является основой для ввода и вывода в Ruby.

Класс File является единственным классом в ядре Ruby, который является подклассом IO. Некоторые классы в стандартной библиотеке Ruby также являются подклассами IO; к ним относятся TCPSocket и UDPSocket.

Глобальная константа ARGF (также доступная как $<) предоставляет поток, подобный IO, который позволяет получить доступ ко всем путям файлов, найденным в ARGV (или найденным в STDIN, если ARGV пуст). ARGF сам по себе не является подклассом IO.

Класс StringIO предоставляет поток, подобный IO, который обрабатывает String. StringIO сам по себе не является подклассом IO.

Важные объекты, основанные на IO, включают:

  • $stdin.

  • $stdout.

  • $stderr.

  • Экземпляры класса File.

Экземпляр IO может быть создан с помощью:

  • IO.new: возвращает новый объект IO для данного целочисленного дескриптора файла.

  • IO.open: передает новый объект IO в данный блок.

  • IO.popen: возвращает новый объект IO, подключенный к $stdin и $stdout вновь запущенного дочернего процесса.

  • Kernel#open: Возвращает новый объект IO, подключенный к заданному источнику: потоку, файлу или дочернему процессу.

Как и поток файла, поток IO имеет:

  • Режим чтения/записи, который может быть только для чтения, только для записи или для чтения/записи; см. Режим чтения/записи.

  • Режим данных, который может быть только текстовым или двоичным; см. Режим данных.

  • Внутренние и внешние кодировки; см. Кодировки.

И, как и другие потоки IO, он имеет:

  • Позицию, которая определяет, где в потоке будет происходить следующее чтение или запись; см. Позиция.

  • Номер строки, который является специальной, ориентированной на строки, «позицией» (отличной от упомянутой выше позиции); см. Номер строки.

Расширение io/console

Расширение io/console предоставляет множество методов для взаимодействия с консолью; его подключение добавляет множество методов к классу IO.

Примеры файлов

Многие примеры здесь используют эти переменные:

# English text with newlines.
text = <<~EOT
  First line
  Second line

  Fourth line
  Fifth line
EOT

# Russian text.
russian = "\u{442 435 441 442}" # => "тест"

# Binary data.
data = "\u9990\u9991\u9992\u9993\u9994"

# Text file.
File.write('t.txt', text)

# File with Russian text.
File.write('t.rus', russian)

# File with binary data.
f = File.new('t.dat', 'wb:UTF-16')
f.write(data)
f.close

Параметры открытия

Ряд методов IO принимают необязательные ключевые аргументы, которые определяют, как будет открыт новый поток:

  • :mode: Режим потока.

  • :flags: Целочисленные флаги открытия файлов; если mode также указаны, то оба значения объединяются побитовым ИЛИ.

  • :external_encoding: Внешняя кодировка потока.

  • :internal_encoding: Внутренняя кодировка потока. '-' — синоним для значения по умолчанию внутренней кодировки. Если значение равно nil преобразование не происходит.

  • :encoding: Указывает внешние и внутренние кодировки как 'extern:intern'.

  • :textmode: Если имеет истинное значение, задаёт режим как только для текста, в противном случае — двоичный.

  • :binmode: Если имеет истинное значение, задаёт режим как двоичный, в противном случае — только для текста.

  • :autoclose: Если имеет истинное значение, указывает, что fd будет закрыт при закрытии потока; в противном случае он остаётся открытым.

  • :path: Если предоставлено строковое значение, оно используется в inspect и доступно как метод path.

Также доступны параметры, предложенные в String#encode, которые могут управлять преобразованием между внешней и внутренней кодировкой.

Базовый IO

Вы можете выполнить базовый ввод/вывод потока с помощью этих методов, которые обычно работают со строками с несколькими байтами:

  • IO#read: Читает и возвращает часть или все оставшиеся байты из потока.

  • IO#write: Записывает ноль или более строк в поток; каждый объект, который не является строкой, преобразуется с помощью to_s.

Позиция

Поток IO имеет целочисленную позицию ≥ 0, которая является смещением байтов, в котором будет происходить следующее чтение или запись. Новый поток имеет позицию ноль (и номер строки ноль); метод rewind сбрасывает позицию (и номер строки) до нуля.

Соответствующие методы:

  • IO#tell (псевдоним #pos): Возвращает текущую позицию (в байтах) в потоке.

  • IO#pos=: Устанавливает позицию потока на заданное целое число new_position (в байтах).

  • IO#seek: Устанавливает позицию потока на заданное целое число offset (в байтах), относительно заданной позиции whence (указывающей начало, конец или текущую позицию).

  • IO#rewind: Устанавливает позицию потока в начало (также сбрасывая номер строки).

Открытые и закрытые потоки

Новый поток IO может быть открыт для чтения, открыт для записи или для обоих.

Поток автоматически закрывается, когда заявляется сборщиком мусора.

Попытка чтения или записи в закрытый поток вызывает исключение.

Соответствующие методы:

  • IO#close: Закрывает поток для чтения и записи.

  • IO#close_read: Закрывает поток для чтения.

  • IO#close_write: Закрывает поток для записи.

  • IO#closed?: Возвращает, закрыт ли поток.

Конец потока

Вы можете проверить, расположена ли позиция потока в конце потока:

  • IO#eof? (также псевдоним #eof): Возвращает, находится ли поток в конце потока.

Вы можете переместиться в конец потока, используя метод IO#seek:

f = File.new('t.txt')
f.eof? # => false
f.seek(0, :END)
f.eof? # => true
f.close

Или прочитав всё содержимое потока (что медленнее, чем использование IO#seek):

f.rewind
f.eof? # => false
f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.eof? # => true

Потоки строк

Вы можете читать поток IO построчно с помощью этих методов:

  • IO#each_line: Читает каждую оставшуюся строку, передавая её в данный блок.

  • IO#gets: Возвращает следующую строку.

  • IO#readline: Как gets, но вызывает исключение в конце потока.

  • IO#readlines: Возвращает все оставшиеся строки в массиве.

Каждый из этих методов чтения принимает:

  • Необязательный разделитель строк, sep; см. Разделитель строк.

  • Необязательный лимит размера строки, limit; см. Лимит строки.

Для каждого из этих методов чтения чтение может начаться посреди строки, в зависимости от позиции потока; см. Позиция:

f = File.new('t.txt')
f.pos = 27
f.each_line {|line| p line }
f.close

Вывод:

"rth line\n"
"Fifth line\n"

Вы можете записать в поток IO построчно с помощью этого метода:

  • IO#puts: Записывает объекты в поток.

Разделитель строк

Каждый из этих методов использует разделитель строк, который представляет собой строку, разделяющую строки:

  • IO.foreach.

  • IO.readlines.

  • IO#each_line.

  • IO#gets.

  • IO#readline.

  • IO#readlines.

По умолчанию разделитель строк задается глобальной переменной $/, значение которой по умолчанию "\n". Следующая строка для чтения — это все данные от текущей позиции до следующего разделителя строк:

f = File.new('t.txt')
f.gets # => "First line\n"
f.gets # => "Second line\n"
f.gets # => "\n"
f.gets # => "Fourth line\n"
f.gets # => "Fifth line\n"
f.close

Вы можете указать другой разделитель строк:

f = File.new('t.txt')
f.gets('l')   # => "First l"
f.gets('li')  # => "ine\nSecond li"
f.gets('lin') # => "ne\n\nFourth lin"
f.gets        # => "e\n"
f.close

Существует два специальных разделителя строк:

  • nil: Весь поток читается в одну строку:

    f = File.new('t.txt')
    f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
    f.close
    
  • '' (пустая строка): Читается следующая «абзац» (абзацы разделяются двумя последовательными разделителями строк):

    f = File.new('t.txt')
    f.gets('') # => "First line\nSecond line\n\n"
    f.gets('') # => "Fourth line\nFifth line\n"
    f.close
    

Лимит строки

Каждый из этих методов использует предел строки, который указывает, что количество возвращаемых байтов не может быть (намного) больше, чем заданный limit;

  • IO.foreach.

  • IO.readlines.

  • IO#each_line.

  • IO#gets.

  • IO#readline.

  • IO#readlines.

Многобайтовый символ не будет разделен, поэтому строка может быть немного длиннее заданного предела.

Если limit не указан, строка определяется только sep.

# Text with 1-byte characters.
File.open('t.txt') {|f| f.gets(1) }  # => "F"
File.open('t.txt') {|f| f.gets(2) }  # => "Fi"
File.open('t.txt') {|f| f.gets(3) }  # => "Fir"
File.open('t.txt') {|f| f.gets(4) }  # => "Firs"
# No more than one line.
File.open('t.txt') {|f| f.gets(10) } # => "First line"
File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
File.open('t.txt') {|f| f.gets(12) } # => "First line\n"

# Text with 2-byte characters, which will not be split.
File.open('t.rus') {|f| f.gets(1).size } # => 1
File.open('t.rus') {|f| f.gets(2).size } # => 1
File.open('t.rus') {|f| f.gets(3).size } # => 2
File.open('t.rus') {|f| f.gets(4).size } # => 2

Разделитель строк и лимит строки

С аргументами sep и limit объединены оба поведения:

  • Возвращает следующую строку, как определено разделителем строк sep.

  • Но возвращает не более байтов, чем разрешено пределом.

Пример:

File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
File.open('t.txt') {|f| f.gets('li', 2) }  # => "Fi"

Номер строки

Поток ввода-вывода считывания имеет целое неотрицательное число номер строки.

Соответствующие методы:

  • IO#lineno: Возвращает номер строки.

  • IO#lineno=: Сбрасывает и возвращает номер строки.

Если не изменено вызовом метода IO#lineno=, номер строки — это количество прочитанных строк определёнными методами ориентированными на строки, в соответствии с заданным разделителем строк sep:

  • IO.foreach: Увеличивает номер строки при каждом вызове блока.

  • IO#each_line: Увеличивает номер строки при каждом вызове блока.

  • IO#gets: Увеличивает номер строки.

  • IO#readline: Увеличивает номер строки.

  • IO#readlines: Увеличивает номер строки для каждой прочитанной строки.

Новый поток изначально имеет номер строки ноль (и позицию ноль); метод rewind сбрасывает номер строки (и позицию) до нуля:

f = File.new('t.txt')
f.lineno # => 0
f.gets   # => "First line\n"
f.lineno # => 1
f.rewind
f.lineno # => 0
f.close

Чтение строк из потока обычно изменяет его номер строки:

f = File.new('t.txt', 'r')
f.lineno   # => 0
f.readline # => "This is line one.\n"
f.lineno   # => 1
f.readline # => "This is the second line.\n"
f.lineno   # => 2
f.readline # => "Here's the third line.\n"
f.lineno   # => 3
f.eof?     # => true
f.close

Итерация по строкам в потоке обычно изменяет его номер строки:

File.open('t.txt') do |f|
  f.each_line do |line|
    p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
  end
end

Вывод:

"position=11 eof?=false lineno=1"
"position=23 eof?=false lineno=2"
"position=24 eof?=false lineno=3"
"position=36 eof?=false lineno=4"
"position=47 eof?=true lineno=5"

В отличие от позиции потока position, номер строки не влияет на то, где произойдёт следующее чтение или запись:

f = File.new('t.txt')
f.lineno = 1000
f.lineno # => 1000
f.gets   # => "First line\n"
f.lineno # => 1001
f.close

Вместе с номером строки связана глобальная переменная $.:

  • При открытии потока $. не устанавливается; его значение наследуется из предыдущей активности в процессе:

    $. = 41
    f = File.new('t.txt')
    $. = 41
    # => 41
    f.close
    
  • При чтении потока #. устанавливается в номер строки для этого потока:

    f0 = File.new('t.txt')
    f1 = File.new('t.dat')
    f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
    $.           # => 5
    f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
    $.           # => 1
    f0.close
    f1.close
    
  • Методы IO#rewind и IO#seek не влияют на $.:

    f = File.new('t.txt')
    f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
    $.          # => 5
    f.rewind
    f.seek(0, :SET)
    $.          # => 5
    f.close
    

Символьный ввод-вывод

Вы можете обрабатывать поток ввода-вывода символ за символом, используя эти методы:

  • IO#getc: Считывает и возвращает следующий символ из потока.

  • IO#readchar: Как getc, но поднимает исключение при достижении конца потока.

  • IO#ungetc: Возвращает ("отбрасывает") символ или целое число в поток.

  • IO#putc: Записывает символ в поток.

  • IO#each_char: Считывает каждый оставшийся символ в потоке, передавая символ в заданный блок.

Байтовый ввод-вывод

Вы можете обрабатывать поток ввода-вывода байт за байтом, используя эти методы:

  • IO#getbyte: Возвращает следующий 8-битный байт как целое число в диапазоне 0..255.

  • IO#readbyte: Как getbyte, но поднимает исключение в конце потока.

  • IO#ungetbyte: Возвращает ("отбрасывает") байт обратно в поток.

  • IO#each_byte: Считывает каждый оставшийся байт в потоке, передавая байт в заданный блок.

Кодпоинтовый ввод-вывод

Вы можете обрабатывать поток ввода-вывода кодпоинт за кодпоинтом:

  • IO#each_codepoint: Считывает каждый оставшийся кодпоинт, передавая его в заданный блок.

Что здесь

Сначала, что где-то ещё. Класс IO:

  • Наследуется от класса Object.

  • Включает модуль Enumerable, который предоставляет десятки дополнительных методов.

Здесь класс IO предоставляет методы, полезные для:

  • Создание

  • Чтение

  • Запись

  • Позиционирование

  • Итерация

  • Настройки

  • Запросы

  • Буферизация

  • Доступ на низком уровне

  • Другое

Создание

  • ::new (алиас ::for_fd): Создаёт и возвращает новый объект IO для данного целочисленного дескриптора файла.

  • ::open: Создаёт новый объект IO.

  • ::pipe: Создаёт соединённую пару объектов IO для чтения и записи.

  • ::popen: Создаёт объект IO для взаимодействия с подпроцессом.

  • ::select: Выбирает, какие из заданных объектов IO готовы к чтению, записи или имеют ожидаемые исключения.

Чтение

  • ::binread: Возвращает двоичную строку со всеми или подмножеством байтов из данного файла.

  • ::read: Возвращает строку со всеми или подмножеством байтов из данного файла.

  • ::readlines: Возвращает массив строк, являющихся строками из данного файла.

  • getbyte: Возвращает следующий 8-битный байт, прочитанный из self, как целое число.

  • getc: Возвращает следующий символ, прочитанный из self, как строку.

  • gets: Возвращает прочитанную строку из self.

  • pread: Возвращает все или следующие n байтов, прочитанных из self, не обновляя смещение получателя.

  • read: Возвращает все оставшиеся или следующие n байтов, прочитанных из self для заданного n.

  • read_nonblock: следующие n байтов, прочитанных из self для заданного n, в режиме без блокировки.

  • readbyte: Возвращает следующий байт, прочитанный из self; аналогично getbyte, но поднимает исключение при достижении конца потока.

  • readchar: Возвращает следующий символ, прочитанный из self; аналогично getc, но поднимает исключение при достижении конца потока.

  • readline: Возвращает следующую строку, прочитанную из self; аналогично getline, но поднимает исключение при достижении конца потока.

  • readlines: Возвращает массив всех строк, прочитанных из self.

  • readpartial: Возвращает до заданного количества байтов из self.

Запись

  • ::binwrite: Записывает заданную строку в файл по заданному пути в двоичном режиме.

  • ::write: Записывает заданную строку в self.

  • <<: Добавляет заданную строку к self.

  • print: Выводит последнюю прочитанную строку или заданные объекты в self.

  • printf: Записывает в self на основе заданной строки формата и объектов.

  • putc: Записывает символ в self.

  • puts: Записывает строки в self, убеждаясь, что конец строки заканчивается новой строкой.

  • pwrite: Записывает заданную строку по заданному смещению, не обновляя смещение получателя.

  • write: Записывает одну или несколько заданных строк в self.

  • write_nonblock: Записывает одну или несколько заданных строк в self в режиме без блокировки.

Позиционирование

  • lineno: Возвращает текущий номер строки в self.

  • lineno=: Устанавливает номер строки в self.

  • pos (алиас tell): Возвращает текущее байтовое смещение в self.

  • pos=: Устанавливает байтовое смещение в self.

  • reopen: Переустанавливает ассоциацию self с новым или существующим потоком ввода-вывода.

  • rewind: Позиционирует self в начало ввода.

  • seek: Устанавливает смещение для self относительно заданной позиции.

Итерация

  • ::foreach: Выдает каждую строку заданного файла в блок.

  • each (алиас each_line): Вызывает заданный блок для каждой последующей строки в self.

  • each_byte: Вызывает заданный блок для каждого последующего байта в self как целое число.

  • each_char: Вызывает заданный блок для каждого последующего символа в self как строку.

  • each_codepoint: Вызывает заданный блок для каждого последующего кодового пункта в self как целое число.

Настройки

  • autoclose=: Устанавливает, закрывает ли self автоматически.

  • binmode: Устанавливает self в двоичный режим.

  • close: Закрывает self.

  • close_on_exec=: Устанавливает флаг закрытия при выполнении.

  • close_read: Закрывает self для чтения.

  • close_write: Закрывает self для записи.

  • set_encoding: Устанавливает кодировку для self.

  • set_encoding_by_bom: Устанавливает кодировку для self, на основе её Unicode-метки порядка байтов.

  • sync=: Устанавливает режим синхронизации на заданное значение.

Запросы

  • autoclose?: Возвращает, закрывает ли self автоматически.

  • binmode?: Возвращает, находится ли self в двоичном режиме.

  • close_on_exec?: Возвращает флаг закрытия при выполнении для self.

  • closed?: Возвращает, закрыт ли self.

  • eof? (алиас eof): Возвращает, находится ли self в конце потока.

  • external_encoding: Возвращает объект внешней кодировки для self.

  • fileno (алиас to_i): Возвращает целое число дескриптора файла для self.

  • internal_encoding: Возвращает объект внутренней кодировки для self.

  • pid: Возвращает идентификатор процесса дочернего процесса, связанного с self, если self был создан методом ::popen.

  • stat: Возвращает объект File::Stat содержащий информацию о статусе для self.

  • sync: Возвращает, находится ли self в режиме синхронизации.

  • tty? (алиас isatty): Возвращает, является ли self терминалом.

Буферизация

  • fdatasync: Немедленно записывает все буферизованные данные в self на диск.

  • flush: Очищает любые буферизованные данные в self в операционной системе.

  • fsync: Немедленно записывает все буферизованные данные и атрибуты в self на диск.

  • ungetbyte: Добавляет в буфер для self заданный байт целого числа или строку.

  • ungetc: Добавляет в буфер для self заданную строку.

Доступ к низкому уровню

  • ::sysopen: Открывает файл по заданному пути, возвращая целое число дескриптора файла.

  • advise: Объявляет намерение получить доступ к данным из self определенным образом.

  • fcntl: Передает команду низкого уровня файлу, заданному дескриптором файла.

  • ioctl: Передает команду низкого уровня устройству, заданному дескриптором файла.

  • sysread: Возвращает до следующих n байт, прочитанных из self с использованием низкоуровневого чтения.

  • sysseek: Устанавливает смещение для self.

  • syswrite: Записывает заданную строку в self с использованием низкоуровневой записи.

Другое

  • ::copy_stream: Копирует данные из источника в пункт назначения, каждый из которых является путем к файлу или объектом типа IO.

  • ::try_convert: Возвращает новый объект IO, полученный из преобразования заданного объекта.

  • inspect: Возвращает строковое представление self.

Константы

EWOULDBLOCKWaitReadable

EAGAINWaitReadable

EWOULDBLOCKWaitWritable

EAGAINWaitWritable

PRIORITY
READABLE
SEEK_CUR

Set Позиция ввода-вывода от текущей позиции.

SEEK_DATA

Set Позиция ввода-вывода до следующего местоположения содержащего данные.

SEEK_END

Set Позиция ввода-вывода от конца.

SEEK_HOLE

Set Позиция ввода-вывода до следующей дыры.

SEEK_SET

Set Позиция ввода-вывода с начала.

WRITABLE

Методы публичного класса

binread(command, length = nil, offset = 0) → строка или nil Показать исходный код
binread(path, length = nil, offset = 0) → строка или nil
static VALUE
rb_io_s_binread(int argc, VALUE *argv, VALUE io)
{
    VALUE offset;
    struct foreach_arg arg;
    enum {
        fmode = FMODE_READABLE|FMODE_BINMODE,
        oflags = O_RDONLY
#ifdef O_BINARY
                |O_BINARY
#endif
    };
    convconfig_t convconfig = {NULL, NULL, 0, Qnil};

    rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
    FilePathValue(argv[0]);
    convconfig.enc = rb_ascii8bit_encoding();
    arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
    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);
}

Ведет себя как IO.read, за исключением того, что поток открывается в двоичном режиме с кодировкой ASCII-8BIT.

При вызове из класса IO (но не подклассов IO), этот метод имеет потенциальные уязвимости безопасности при использовании небезопасного ввода; см. Вектор атаки «Инъекция команд».

binwrite(command, string, offset = 0) → целое число Показать исходный код
binwrite(path, string, offset = 0) → целое число
static VALUE
rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
{
    return io_s_write(argc, argv, io, 1);
}

Ведет себя как IO.write, за исключением того, что поток открывается в двоичном режиме с кодировкой ASCII-8BIT.

При вызове из класса IO (но не подклассов IO), этот метод имеет потенциальные уязвимости безопасности при использовании небезопасного ввода; см. Вектор атаки «Инъекция команд».

console → #<File:/dev/tty> Показать исходный код
console(sym, *args)
static VALUE
console_dev(int argc, VALUE *argv, VALUE klass)
{
    VALUE con = 0;
    rb_io_t *fptr;
    VALUE sym = 0;

    rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
    if (argc) {
        Check_Type(sym = argv[0], T_SYMBOL);
    }
    if (klass == rb_cIO) klass = rb_cFile;
    if (rb_const_defined(klass, id_console)) {
        con = rb_const_get(klass, id_console);
        if (!RB_TYPE_P(con, T_FILE) ||
            (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
            rb_const_remove(klass, id_console);
            con = 0;
        }
    }
    if (sym) {
        if (sym == ID2SYM(id_close) && argc == 1) {
            if (con) {
                rb_io_close(con);
                rb_const_remove(klass, id_console);
                con = 0;
            }
            return Qnil;
        }
    }
    if (!con) {
        VALUE args[2];
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
# define CONSOLE_DEVICE "/dev/tty"
#elif defined _WIN32
# define CONSOLE_DEVICE "con$"
# define CONSOLE_DEVICE_FOR_READING "conin$"
# define CONSOLE_DEVICE_FOR_WRITING "conout$"
#endif
#ifndef CONSOLE_DEVICE_FOR_READING
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
#endif
#ifdef CONSOLE_DEVICE_FOR_WRITING
        VALUE out;
        rb_io_t *ofptr;
#endif
        int fd;

#ifdef CONSOLE_DEVICE_FOR_WRITING
        fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
        if (fd < 0) return Qnil;
        rb_update_max_fd(fd);
        args[1] = INT2FIX(O_WRONLY);
        args[0] = INT2NUM(fd);
        out = rb_class_new_instance(2, args, klass);
#endif
        fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
        if (fd < 0) {
#ifdef CONSOLE_DEVICE_FOR_WRITING
            rb_io_close(out);
#endif
            return Qnil;
        }
        rb_update_max_fd(fd);
        args[1] = INT2FIX(O_RDWR);
        args[0] = INT2NUM(fd);
        con = rb_class_new_instance(2, args, klass);
        GetOpenFile(con, fptr);
        fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
#ifdef CONSOLE_DEVICE_FOR_WRITING
        GetOpenFile(out, ofptr);
        ofptr->pathv = fptr->pathv;
        fptr->tied_io_for_writing = out;
        ofptr->mode |= FMODE_SYNC;
#endif
        fptr->mode |= FMODE_SYNC;
        rb_const_set(klass, id_console, con);
    }
    if (sym) {
        return rb_f_send(argc, argv, con);
    }
    return con;
}

Возвращает экземпляр File, открытый для консоли.

Если sym задано, оно будет отправлено в открытую консоль с args и результат будет возвращен вместо объекта консоли IO самого.

Для использования этого метода необходимо подключать «io/console».

console_size()
Псевдоним для: default_console_size
copy_stream(src, dst, src_length = nil, src_offset = 0) → целое число Показать исходный код
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;

    st.src_fptr = NULL;
    st.dst_fptr = NULL;

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

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

    rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);

    return OFFT2NUM(st.total);
}

Копирует данные из заданного src в заданный dst, возвращая количество скопированных байтов.

  • Заданный src должен быть одним из следующих:

    • Путь к файлу для чтения, из которого необходимо считать исходные данные.

    • Объект, похожий на IO, открытый для чтения и способный реагировать на метод :readpartial или метод :read.

  • Заданный dst должен быть одним из следующих:

    • Путь к файлу для записи, в который необходимо записать данные.

    • Объект, похожий на IO, открытый для записи и способный реагировать на метод :write.

В примерах здесь используется файл t.txt в качестве источника:

File.read('t.txt')
# => "First line\nSecond line\n\nThird line\nFourth line\n"
File.read('t.txt').size # => 47

Если заданы только аргументы src и dst, весь исходный поток копируется:

# Paths.
IO.copy_stream('t.txt', 't.tmp')  # => 47

# IOs (recall that a File is also an IO).
src_io = File.open('t.txt', 'r') # => #<File:t.txt>
dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
IO.copy_stream(src_io, dst_io)   # => 47
src_io.close
dst_io.close

С аргументом src_length — целым числом без знака, копируется не более этого количества байтов:

IO.copy_stream('t.txt', 't.tmp', 10) # => 10
File.read('t.tmp')                   # => "First line"

С аргументом src_offset также заданным, исходный поток читается, начиная с этого смещения:

IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
IO.read('t.tmp')                         # => "Second line"
default_console_size() Показать исходный код
# File ext/io/console/lib/console/size.rb, line 3
def IO.default_console_size
  [
    ENV["LINES"].to_i.nonzero? || 25,
    ENV["COLUMNS"].to_i.nonzero? || 80,
  ]
end

Возвращает размер окна консоли.

Также алиасом является: console_size
for_fd(fd, mode = 'r', **opts) → io Показать исходный код
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;
}

Синоним для IO.new.

foreach(path, sep = $/, **opts) {|line| block } → nil Показать исходный код
...
static VALUE
rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
{
    VALUE opt;
    int orig_argc = argc;
    struct foreach_arg arg;
    struct getline_arg garg;

    argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
    RETURN_ENUMERATOR(self, orig_argc, argv);
    extract_getline_args(argc-1, argv+1, &garg);
    open_key_args(self, argc, argv, opt, &arg);
    if (NIL_P(arg.io)) return Qnil;
    extract_getline_opts(opt, &garg);
    check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
    return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
}

Вызывает блок с каждой последующей строкой, считанной из потока.

При вызове из класса IO (но не подклассов IO), этот метод имеет потенциальные уязвимости безопасности при использовании небезопасного ввода; см. Вектор атаки «Инъекция команд».

Первый аргумент должен быть строкой, которая является одной из следующих:

  • Путь: если self является подклассом IO (например, File), или если строка *не* начинается с символа трубы ('|'), строка является путем к файлу.

  • Команда: если self является классом IO, и если строка начинается с символа трубы, остальная часть строки — это команда, которая должна быть выполнена как дочерний процесс. Это использование имеет потенциальные уязвимости безопасности при использовании небезопасного ввода; см. Вектор атаки «Инъекция команд».

При задании только аргумента path, анализирует строки из файла в соответствии с заданным path, как определено разделителем строк по умолчанию, и вызывает блок с каждой последующей строкой:

File.foreach('t.txt') {|line| p line }
new(fd, mode = 'r', **opts) → io Показать исходный код
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) < 0) 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
    VALUE path = Qnil;

    if (!NIL_P(opt)) {
        if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
            fmode |= FMODE_PREP;
        }

        path = rb_hash_aref(opt, RB_ID2SYM(idPath));
        if (!NIL_P(path)) {
            StringValue(path);
            path = rb_str_new_frozen(path);
        }
    }

    MakeOpenFile(io, fp);
    fp->self = io;
    fp->fd = fd;
    fp->mode = fmode;
    fp->encs = convconfig;
    fp->pathv = path;
    fp->timeout = Qnil;
    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;
}

Создает и возвращает новый объект IO (поток файла) из дескриптора файла.

IO.new может быть полезен для взаимодействия с низкоуровневыми библиотеками. Для взаимодействия на более высоком уровне проще создать поток файла с помощью File.open.

Аргумент fd должен быть корректным дескриптором файла (целое число):

path = 't.tmp'
fd = IO.sysopen(path) # => 3
IO.new(fd)            # => #<IO:fd 3>

Новый объект IO не наследует кодировку (потому что у целочисленного дескриптора файла нет кодировки):

fd = IO.sysopen('t.rus', 'rb')
io = IO.new(fd)
io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.

Необязательный аргумент mode (по умолчанию ‘r’) должен задавать корректный режим; см. Режимы доступа:

IO.new(fd, 'w')         # => #<IO:fd 3>
IO.new(fd, File::WRONLY) # => #<IO:fd 3>

Необязательные ключевые аргументы opts задают:

  • Параметры открытия.

  • Параметры кодировки.

Примеры:

IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
IO.new(fd, autoclose: true)        # => #<IO:fd 3>
open(fd, mode = 'r', **opts) → io Показать исходный код
open(fd, mode = 'r', **opts) {|io| ... } → объект
static VALUE
rb_io_s_open(int argc, VALUE *argv, VALUE klass)
{
    VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);

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

    return io;
}

Создает новый объект IO с помощью IO.new с заданными аргументами.

Без блока возвращает объект IO.

С блоком вызывает блок с объектом IO и возвращает значение блока.

END_OF_DOCUMENT_MARKER
pipe(**opts) → [read_io, write_io] Показать исходный код
pipe(enc, **opts) → [read_io, write_io]
pipe(ext_enc, int_enc, **opts) → [read_io, write_io]
pipe(**opts) {|read_io, write_io] ...} → object
pipe(enc, **opts) {|read_io, write_io] ...} → object
pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} → object
static VALUE
rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
{
    int pipes[2], state;
    VALUE r, w, args[3], v1, v2;
    VALUE opt;
    rb_io_t *fptr, *fptr2;
    struct io_encoding_set_args ies_args;
    int fmode = 0;
    VALUE ret;

    argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
    if (rb_pipe(pipes) < 0)
        rb_sys_fail(0);

    args[0] = klass;
    args[1] = INT2NUM(pipes[0]);
    args[2] = INT2FIX(O_RDONLY);
    r = rb_protect(io_new_instance, (VALUE)args, &state);
    if (state) {
        close(pipes[0]);
        close(pipes[1]);
        rb_jump_tag(state);
    }
    GetOpenFile(r, fptr);

    ies_args.fptr = fptr;
    ies_args.v1 = v1;
    ies_args.v2 = v2;
    ies_args.opt = opt;
    rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
    if (state) {
        close(pipes[1]);
        io_close(r);
        rb_jump_tag(state);
    }

    args[1] = INT2NUM(pipes[1]);
    args[2] = INT2FIX(O_WRONLY);
    w = rb_protect(io_new_instance, (VALUE)args, &state);
    if (state) {
        close(pipes[1]);
        if (!NIL_P(r)) rb_io_close(r);
        rb_jump_tag(state);
    }
    GetOpenFile(w, fptr2);
    rb_io_synchronized(fptr2);

    extract_binmode(opt, &fmode);

    if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
        rb_io_ascii8bit_binmode(r);
        rb_io_ascii8bit_binmode(w);
    }

#if DEFAULT_TEXTMODE
    if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
        fptr->mode &= ~FMODE_TEXTMODE;
        setmode(fptr->fd, O_BINARY);
    }
#if RUBY_CRLF_ENVIRONMENT
    if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
        fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
    }
#endif
#endif
    fptr->mode |= fmode;
#if DEFAULT_TEXTMODE
    if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
        fptr2->mode &= ~FMODE_TEXTMODE;
        setmode(fptr2->fd, O_BINARY);
    }
#endif
    fptr2->mode |= fmode;

    ret = rb_assoc_new(r, w);
    if (rb_block_given_p()) {
        VALUE rw[2];
        rw[0] = r;
        rw[1] = w;
        return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
    }
    return ret;
}

Создаёт пару конечных точек канала, read_io и write_io, соединённые друг с другом.

Если аргумент enc_string задан, он должен быть строкой, содержащей одно из:

  • Имя кодировки, используемой в качестве внешней кодировки.

  • Разделённые двоеточием имена двух кодировок, используемых в качестве внешней и внутренней кодировок.

Если аргумент int_enc задан, он должен быть объектом Encoding или строкой имени кодировки, которая определяет используемую внутреннюю кодировку; если аргумент ext_enc также задан, он должен быть объектом Encoding или строкой имени кодировки, которая определяет используемую внешнюю кодировку.

Строка, считанная из read_io, помечена внешней кодировкой; если также задана внутренняя кодировка, строка преобразуется и помечена этой кодировкой.

Если задана какая-либо кодировка, необязательные аргументы хеша определяют параметры преобразования.

Необязательные ключевые аргументы opts определяют:

  • Параметры открытия.

  • Параметры кодировки.

Без блока возвращает две конечные точки в массиве:

IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]

При указании блока, вызывает блок с двумя конечными точками; закрывает обе конечные точки и возвращает значение блока:

IO.pipe {|read_io, write_io| p read_io; p write_io }

Вывод:

#<IO:fd 6>
#<IO:fd 7>

Недоступно на всех платформах.

В примере ниже два процесса закрывают концы канала, которыми они не пользуются. Это не просто косметический элемент. Чтение из канала не сгенерирует состояние конца файла, если есть какие-либо писатели, у которых канал всё ещё открыт. В случае родительского процесса 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', **opts) → io Показать исходный код
popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } → object
static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
    VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;

    if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
    if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
    switch (argc) {
      case 2:
        pmode = argv[1];
      case 1:
        pname = argv[0];
        break;
      default:
        {
            int ex = !NIL_P(opt);
            rb_error_arity(argc + ex, 1 + ex, 2 + ex);
        }
    }
    return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
}

Выполняет заданную команду cmd как дочерний процесс, stdin и stdout которого подключены к новому потоку io.

Этот метод имеет потенциальные уязвимости в области безопасности, если вызывается с недоверенными входными данными; см. Инъекция команд.

Если блок не указан, возвращает новый поток, который в зависимости от заданного mode может быть открыт для чтения, записи или того и другого. Поток следует явно закрыть (в конечном счёте), чтобы избежать утечек ресурсов.

Если блок задан, поток передаётся блоку (снова, открытому для чтения, записи или того и другого); по завершении работы блока поток закрывается, значение блока присваивается глобальной переменной $? и возвращается.

Необязательный аргумент mode может быть любым допустимым режимом ввода/вывода. См. Режимы доступа.

Обязательный аргумент cmd определяет, что произойдёт:

  • Процесс разветвляется.

  • Указанная программа запускается в оболочке.

  • Указанная программа запускается со указанными аргументами.

  • Указанная программа запускается со указанными аргументами и указанным argv0.

Каждый из этих пунктов описан ниже.

Необязательный аргумент хеш env определяет пары имя/значение, которые должны быть добавлены в переменные среды для дочернего процесса:

IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
  pipe.puts 'puts ENV["FOO"]'
  pipe.close_write
  pipe.gets
end => "bar\n"

Необязательные ключевые аргументы opts определяют:

  • Параметры открытия.

  • Параметры кодировки.

  • Параметры для Kernel#spawn.

Разветвлённый процесс

Когда аргумент cmd равен строке из одного символа '-', заставляет процесс разветвиться:

IO.popen('-') do |pipe|
  if pipe
    $stderr.puts "In parent, child pid is #{pipe.pid}\n"
  else
    $stderr.puts "In child, pid is #{$$}\n"
  end
end

Вывод:

In parent, child pid is 26253
In child, pid is 26253

Обратите внимание, что это не поддерживается на всех платформах.

Дочерний процесс в оболочке

Когда аргумент cmd представляет собой единственную строку (но не '-'), программа с именем cmd запускается как команда оболочки:

IO.popen('uname') do |pipe|
  pipe.readlines
end

Вывод:

213

Другой пример:

IO.popen('/bin/sh', 'r+') do |pipe|
  pipe.puts('ls')
  pipe.close_write
  $stderr.puts pipe.readlines.size
end

Вывод:

["Linux\n"]

Дочерний процесс программы

Когда аргумент cmd представляет собой массив строк, программа с именем cmd[0] запускается со всеми элементами cmd в качестве аргументов:

IO.popen(['du', '..', '.']) do |pipe|
  $stderr.puts pipe.readlines.size
end

Вывод:

1111

Дочерний процесс программы с argv0

Когда аргумент cmd представляет собой массив, первый элемент которого — массив из двух строк, а остальные элементы (если есть) — строки:

  • cmd[0][0] (первая строка вложенного массива) — имя программы, которая запускается.

  • cmd[0][1] (вторая строка вложенного массива) устанавливается в качестве argv[0] программы.

  • cmd[1..-1] (строки во внешнем массиве) — аргументы программы.

Пример (устанавливает $0 в ‘foo’):

IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"

Некоторые специальные примеры

# 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 Kernel#spawn option. See Kernel#spawn.
IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
  ls_result_with_error = io.read
end

# Use mixture of spawn options and IO options.
IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
  ls_result_with_error = io.read
end

 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;

Возникают исключения, которые IO.pipe и Kernel.spawn генерируют.

read(command, length = nil, offset = 0, **opts) → string or nil Показать исходный код
read(path, length = nil, offset = 0, **opts) → string or nil
static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
    VALUE opt, offset;
    struct foreach_arg arg;

    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
    open_key_args(io, argc, argv, opt, &arg);
    if (NIL_P(arg.io)) return Qnil;
    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);
        }
        if (arg.argc == 2) arg.argc = 1;
    }
    return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}

Открывает поток, считывает и возвращает часть или всё его содержимое, закрывает поток; возвращает nil если байты не были считаны.

Когда вызывается из класса IO (но не из подклассов IO), этот метод имеет потенциальные уязвимости в области безопасности, если вызывается с недоверенными входными данными; см. Инъекция команд.

Первый аргумент должен быть строкой; его значение зависит от того, начинается ли она с символа канала ('|'):

  • Если да (и если self — IO), остальная часть строки — команда, которая должна быть выполнена как дочерний процесс.

  • В противном случае, строка — путь к файлу.

При указании только аргумента command выполняет команду в оболочке, возвращает всё её $stdout:

IO.read('| cat t.txt')
# => "First line\nSecond line\n\nThird line\nFourth line\n"

При указании только аргумента path считывает в текстовом режиме и возвращает всё содержимое файла по заданному пути:

IO.read('t.txt')
# => "First line\nSecond line\n\nThird line\nFourth line\n"

В Windows текстовый режим может прекратить чтение и оставить байты в файле непрочитанными при обнаружении определённых специальных байтов. Рассмотрите использование IO.binread, если должны быть считаны все байты файла.

Для обеих форм, команды и пути, оставшиеся аргументы одинаковы.

При указании аргумента length, возвращает length байтов, если доступно:

IO.read('t.txt', 7) # => "First l"
IO.read('t.txt', 700)
# => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"

При указании аргументов length и offset, возвращает length байтов, если доступно, начиная с указанного offset:

IO.read('t.txt', 10, 2)   # => "rst line\nS"
IO.read('t.txt', 10, 200) # => nil

Необязательные ключевые аргументы opts определяют:

  • Параметры открытия.

  • Параметры кодировки.

readlines(command, sep = $/, **opts) → array Показать исходный код
readlines(command, limit, **opts) → array
readlines(command, sep, limit, **opts) → array
readlines(path, sep = $/, **opts) → array
readlines(path, limit, **opts) → array
readlines(path, sep, limit, **opts) → array
static VALUE
rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
{
    VALUE opt;
    struct foreach_arg arg;
    struct getline_arg garg;

    argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
    extract_getline_args(argc-1, argv+1, &garg);
    open_key_args(io, argc, argv, opt, &arg);
    if (NIL_P(arg.io)) return Qnil;
    extract_getline_opts(opt, &garg);
    check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
    return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
}

Возвращает массив всех строк, прочитанных из потока.

При вызове из класса IO (но не из подклассов IO) этот метод может иметь потенциальные уязвимости безопасности, если используется с ненадежными данными; см. Внедрение команд.

Первый аргумент должен быть строкой; его значение зависит от того, начинается ли она с символа трубы ('|'):

  • Если да (и если self является IO), остальная часть строки — это команда, которая будет выполнена как дочерний процесс.

  • В противном случае, строка — это путь к файлу.

При указании только аргумента command, выполняется команда в оболочке, её стандартный вывод ($stdout) разбирается на строки, как определяется разделитель строк по умолчанию, и эти строки возвращаются в массиве:

IO.readlines('| cat t.txt')
# => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]

При указании только аргумента path, строки из файла по заданному path разбираются, как определяется разделитель строк по умолчанию, и эти строки возвращаются в массиве:

IO.readlines('t.txt')
# => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]

Для обоих форм, команды и пути, оставшиеся аргументы одинаковы.

При указании аргумента sep , строки разбираются, как определяется этот разделитель строк (см. Разделитель строк):

# Ordinary separator.
IO.readlines('t.txt', 'li')
# =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
# Get-paragraphs separator.
IO.readlines('t.txt', '')
# => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
# Get-all separator.
IO.readlines('t.txt', nil)
# => ["First line\nSecond line\n\nThird line\nFourth line\n"]

При указании аргумента limit , строки разбираются, как определяется разделитель строк по умолчанию и заданный лимит длины строки (см. Лимит длины строки):

IO.readlines('t.txt', 7)
# => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]

При указании аргументов sep и limit , строки разбираются, как определяется заданный разделитель строк и заданный лимит длины строки (см. Разделитель строк и лимит длины строки):

Необязательные ключевые аргументы opts задают:

  • Параметры открытия.

  • Параметры кодировки.

  • Параметры строк.

select(read_ios, write_ios = [], error_ios = [], timeout = nil) → array or nil Показать исходный код
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
    VALUE scheduler = rb_fiber_scheduler_current();
    if (scheduler != Qnil) {
        // It's optionally supported.
        VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
        if (!UNDEF_P(result)) return result;
    }

    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);
}

Вызывает системный вызов select(2), который отслеживает несколько дескрипторов файлов, ожидая, пока один или несколько дескрипторов файлов не станут готовы к какому-либо типу операции ввода-вывода.

Не реализовано на всех платформах.

Каждый из аргументов read_ios, write_ios, и error_ios является массивом объектов IO.

Аргумент timeout — это целочисленное значение интервала времени ожидания в секундах.

Метод отслеживает объекты IO, указанные во всех трёх массивах, ожидая, пока некоторые из них не станут готовы; возвращает 3-элементный массив, элементы которого:

  • Массив объектов в read_ios , готовых к чтению.

  • Массив объектов в write_ios , готовых к записи.

  • Массив объектов в error_ios , у которых есть ожидаемые исключения.

Если ни один объект не станет готовым в течение заданного timeout, возвращается nil.

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 и 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, сокеты pipe, сокеты, когда несколько процессов читают из потока.

Наконец, разработчики ядра Linux не гарантируют, что возможность чтения select(2) означает возможность чтения последующего read(2), даже для одного процесса; см. select(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

Пример:

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
sysopen(path, mode = 'r', perm = 0666) → integer Показать исходный код
static VALUE
rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
{
    VALUE fname, vmode, vperm;
    VALUE intmode;
    int oflags, fd;
    mode_t perm;

    rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
    FilePathValue(fname);

    if (NIL_P(vmode))
        oflags = O_RDONLY;
    else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
        oflags = NUM2INT(intmode);
    else {
        SafeStringValue(vmode);
        oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
    }
    if (NIL_P(vperm)) perm = 0666;
    else              perm = NUM2MODET(vperm);

    RB_GC_GUARD(fname) = rb_str_new4(fname);
    fd = rb_sysopen(fname, oflags, perm);
    return INT2NUM(fd);
}

Открывает файл по заданному пути с заданным режимом и разрешениями; возвращает целочисленный дескриптор файла.

Если файл должен быть читаемым, он должен существовать; если файл должен быть записываемым и не существует, он создаётся с заданными разрешениями:

File.write('t.tmp', '')  # => 0
IO.sysopen('t.tmp')      # => 8
IO.sysopen('t.tmp', 'w') # => 9
try_convert(object) → new_io or nil Показать исходный код
static VALUE
rb_io_s_try_convert(VALUE dummy, VALUE io)
{
    return rb_io_check_io(io);
}

Попытка преобразовать object в объект IO через метод to_io; возвращает новый объект IO, если успешно, или nil в противном случае:

IO.try_convert(STDOUT)   # => #<IO:<STDOUT>>
IO.try_convert(ARGF)     # => #<IO:<STDIN>>
IO.try_convert('STDOUT') # => nil
write(command, data, **opts) → integer Показать исходный код
write(path, data, offset = 0, **opts) → integer
static VALUE
rb_io_s_write(int argc, VALUE *argv, VALUE io)
{
    return io_s_write(argc, argv, io, 0);
}

Открывает поток, записывает в него заданные data и закрывает поток; возвращает количество записанных байтов.

При вызове из класса IO (но не из подклассов IO) этот метод имеет потенциальные уязвимости безопасности при вызове с недоверенным вводом; см. Инъекция команд.

Первый аргумент должен быть строкой; его значение зависит от того, начинается ли она с символа трубы ('|'):

  • Если да (и если self является IO), остальная часть строки — это команда, которая будет выполнена как дочерний процесс.

  • В противном случае, строка — это путь к файлу.

С аргументом command , выполняет команду в оболочке, передает data через стандартный ввод, записывает её вывод в $stdout и возвращает длину заданных data:

IO.write('| cat', 'Hello World!') # => 12

Вывод:

Hello World!

С аргументом path , записывает заданные data в файл по этому пути:

IO.write('t.tmp', 'abc')    # => 3
File.read('t.tmp')          # => "abc"

Если offset равно нулю (по умолчанию), файл перезаписывается:

IO.write('t.tmp', 'A')      # => 1
File.read('t.tmp')          # => "A"

Если offset находится внутри содержимого файла, файл частично перезаписывается:

IO.write('t.tmp', 'abcdef') # => 3
File.read('t.tmp')          # => "abcdef"
# Offset within content.
IO.write('t.tmp', '012', 2) # => 3
File.read('t.tmp')          # => "ab012f"

Если offset находится вне содержимого файла, файл заполняется нулевыми символами "\u0000":

IO.write('t.tmp', 'xyz', 10) # => 3
File.read('t.tmp')           # => "ab012f\u0000\u0000\u0000\u0000xyz"

Необязательные ключевые аргументы opts задают:

  • Параметры открытия.

  • Параметры кодирования.

Открытые методы экземпляра

self << object → self Show source
VALUE
rb_io_addstr(VALUE io, VALUE str)
{
    rb_io_write(io, str);
    return io;
}

Записывает заданный object в self, который должен быть открыт для записи (см. Режимы доступа); возвращает self; если object не является строкой, он преобразуется с помощью метода to_s:

$stdout << 'Hello' << ', ' << 'World!' << "\n"
$stdout << 'foo' << :bar << 2 << "\n"

Вывод:

Hello, World!
foobar2
advise(advice, offset = 0, len = 0) → nil Show source
static VALUE
rb_io_advise(int argc, VALUE *argv, VALUE io)
{
    VALUE advice, offset, len;
    rb_off_t off, l;
    rb_io_t *fptr;

    rb_scan_args(argc, argv, "12", &advice, &offset, &len);
    advice_arg_check(advice);

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

    off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
    l   = NIL_P(len)    ? 0 : NUM2OFFT(len);

#ifdef HAVE_POSIX_FADVISE
    return do_io_advise(fptr, advice, off, l);
#else
    ((void)off, (void)l);       /* Ignore all hint */
    return Qnil;
#endif
}

Вызывает системный вызов Posix posix_fadvise(2), который объявляет о намерении получить доступ к данным из текущего файла определенным образом.

Аргументы и результаты зависят от платформы.

Соответствующие данные задаются:

  • offset: Смещение первого байта данных.

  • len: Количество байтов, к которым будет осуществлен доступ; если len равно нулю или больше, чем количество оставшихся байтов, будут доступны все оставшиеся байты.

Аргумент advice является одним из следующих символов:

  • :normal: Приложение не дает никаких рекомендаций относительно своего шаблона доступа к указанным данным. Если для открытого файла не дано никаких рекомендаций, это является предположением по умолчанию.

  • :sequential: Приложение ожидает доступа к указанным данным последовательно (считывая меньшие смещения до больших).

  • :random: Доступ к указанным данным будет осуществляться в произвольном порядке.

  • :noreuse: Доступ к указанным данным будет осуществляться только один раз.

  • :willneed: Доступ к указанным данным будет осуществляться в ближайшем будущем.

  • :dontneed: Доступ к указанным данным не будет осуществляться в ближайшем будущем.

Не реализовано на всех платформах.

autoclose = bool → true or false Show source
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 autoclose;
}

Устанавливает флаг автоматического закрытия.

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

f = open("/dev/null")
IO.for_fd(f.fileno).autoclose = false
# ...
f.gets # won't cause Errno::EBADF
autoclose? → true or false Show source
static VALUE
rb_io_autoclose_p(VALUE io)
{
    rb_io_t *fptr = RFILE(io)->fptr;
    rb_io_check_closed(fptr);
    return RBOOL(!(fptr->mode & FMODE_PREP));
}

Возвращает true, если базовый дескриптор файла ios будет автоматически закрыт при его завершении, в противном случае false.

beep() Show source
static VALUE
console_beep(VALUE io)
{
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
#ifdef _WIN32
    (void)fd;
    MessageBeep(0);
#else
    if (write(fd, "\a", 1) < 0)
        sys_fail_fptr(fptr);
#endif
    return io;
}
binmode → self Show source
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 Show source
static VALUE
rb_io_binmode_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    return RBOOL(fptr->mode & FMODE_BINMODE);
}

Возвращает true, если поток находится в двоичном режиме, false в противном случае. См. Режим данных.

check_winsize_changed() Show source
static VALUE
console_check_winsize_changed(VALUE io)
{
    rb_io_t *fptr;
    HANDLE h;
    DWORD num;

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
    while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
        INPUT_RECORD rec;
        if (ReadConsoleInput(h, &rec, 1, &num)) {
            if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
                rb_yield(Qnil);
            }
        }
    }
    return io;
}
clear_screen() Show source
static VALUE
console_clear_screen(VALUE io)
{
    console_erase_screen(io, INT2FIX(2));
    console_goto(io, INT2FIX(0), INT2FIX(0));
    return io;
}
close → nil Show source
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;
}

Закрывает поток как для чтения, так и для записи, если он открыт для одного из них или для обоих; возвращает nil. См. Открытые и закрытые потоки.

Если поток открыт для записи, перед закрытием сбрасывает все буферизованные записи в операционную систему.

Если поток был открыт с помощью IO.popen, устанавливает глобальную переменную $? (код выхода дочернего процесса).

Пример:

IO.popen('ruby', 'r+') do |pipe|
  puts pipe.closed?
  pipe.close
  puts $?
  puts pipe.closed?
end

Вывод:

false
pid 13760 exit 0
true

Связанные: IO#close_read, IO#close_write, IO#closed?.

close_on_exec = bool → true or false Show source
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 != 0) 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 != 0) rb_sys_fail_path(fptr->pathv);
        }
    }
    return Qnil;
}

Устанавливает флаг close-on-exec.

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 по умолчанию устанавливает флаги close-on-exec для всех дескрипторов файлов начиная с Ruby 2.0.0. Поэтому вам не нужно устанавливать его самостоятельно. Кроме того, сброс флага close-on-exec может привести к утечке дескрипторов файлов, если другой поток использует fork() и exec() (например, с помощью метода system()). Если вам действительно необходимо наследование дескриптора файла дочернему процессу, используйте аргумент spawn(), например, fd=>fd.

close_on_exec? → true or false Show source
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;
}

Возвращает true, если поток будет закрыт при exec, false в противном случае:

f = File.open('t.txt')
f.close_on_exec? # => true
f.close_on_exec = false
f.close_on_exec? # => false
f.close
close_read → nil Show source
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);
}

Закрывает поток для чтения, если он открыт для чтения; возвращает nil. См. Открытые и закрытые потоки.

Если поток был открыт с помощью IO.popen и также закрыт для записи, устанавливает глобальную переменную $? (код выхода дочернего процесса).

Пример:

IO.popen('ruby', 'r+') do |pipe|
  puts pipe.closed?
  pipe.close_write
  puts pipe.closed?
  pipe.close_read
  puts $?
  puts pipe.closed?
end

Вывод:

false
false
pid 14748 exit 0
true

Связанные: IO#close, IO#close_write, IO#closed?.

close_write → nil Show source
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;
}

Закрывает поток для записи, если он открыт для записи; возвращает nil. См. Открытые и закрытые потоки.

Сбрасывает все буферизованные записи в операционную систему перед закрытием.

Если поток был открыт с помощью IO.popen и также закрыт для чтения, устанавливает глобальную переменную $? (код выхода дочернего процесса).

IO.popen('ruby', 'r+') do |pipe|
  puts pipe.closed?
  pipe.close_read
  puts pipe.closed?
  pipe.close_write
  puts $?
  puts pipe.closed?
end

Вывод:

false
false
pid 15044 exit 0
true

Связанные: IO#close, IO#close_read, IO#closed?.

closed? → true or false Show source
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 RBOOL(0 > fptr->fd);
}

Возвращает true, если поток закрыт как для чтения, так и для записи, false в противном случае. См. Открытые и закрытые потоки.

IO.popen('ruby', 'r+') do |pipe|
  puts pipe.closed?
  pipe.close_read
  puts pipe.closed?
  pipe.close_write
  puts pipe.closed?
end

Вывод:

false
false
true

Связанные: IO#close_read, IO#close_write, IO#close.

console_mode → mode Показать исходный код
static VALUE
console_conmode_get(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) sys_fail_fptr(fptr);

    return conmode_new(cConmode, &t);
}

Возвращает данные, представляющие текущий режим консоли.

Для использования этого метода необходимо подключить «io/console».

console_mode = mode Показать исходный код
static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
    conmode *t, r;
    rb_io_t *fptr;
    int fd;

    TypedData_Get_Struct(mode, conmode, &conmode_type, t);
    r = *t;
    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!setattr(fd, &r)) sys_fail_fptr(fptr);

    return mode;
}

Устанавливает режим консоли в mode.

Для использования этого метода необходимо подключить «io/console».

cooked {|io| } Показать исходный код
static VALUE
console_cooked(VALUE io)
{
    return ttymode(io, rb_yield, io, set_cookedmode, NULL);
}

Возвращает self в режиме cooked.

STDIN.cooked(&:gets)

будет читать и возвращать строку с отображением и редактированием строк.

Для использования этого метода необходимо подключить «io/console».

cooked! Показать исходный код
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)) sys_fail_fptr(fptr);
    set_cookedmode(&t, NULL);
    if (!setattr(fd, &t)) sys_fail_fptr(fptr);
    return io;
}

Включает режим cooked.

Если необходимо вернуть предыдущий режим терминала, используйте io.cooked { … }.

Для использования этого метода необходимо подключить «io/console».

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.Y), UINT2NUM(ws.dwCursorPosition.X));
}
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));
}
cursor_down(p1) Показать исходный код
static VALUE
console_cursor_down(VALUE io, VALUE val)
{
    return console_move(io, +NUM2INT(val), 0);
}
cursor_left(p1) Показать исходный код
static VALUE
console_cursor_left(VALUE io, VALUE val)
{
    return console_move(io, 0, -NUM2INT(val));
}
cursor_right(p1) Показать исходный код
static VALUE
console_cursor_right(VALUE io, VALUE val)
{
    return console_move(io, 0, +NUM2INT(val));
}
cursor_up(p1) Показать исходный код
static VALUE
console_cursor_up(VALUE io, VALUE val)
{
    return console_move(io, -NUM2INT(val), 0);
}
each -> перечислитель Показать исходный код
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;
}

Вызывает блок для каждой оставшейся строки, прочитанной из потока; возвращает self. Ничего не делает, если уже достигнут конец потока; См. Строка IO.

Без аргументов читает строки, определяемые разделителем строк $/;

f = File.new('t.txt')
f.each_line {|line| p line }
f.each_line {|line| fail 'Cannot happen' }
f.close

Вывод:

"First line\n"
"Second line\n"
"\n"
"Fourth line\n"
"Fifth line\n"

Только с строковым аргументом sep, читает строки, определяемые разделителем строк sep; см. Разделитель строк:

f = File.new('t.txt')
f.each_line('li') {|line| p line }
f.close

Вывод:

"First li"
"ne\nSecond li"
"ne\n\nFourth li"
"ne\nFifth li"
"ne\n"

Два специальных значения для sep;

f = File.new('t.txt')
# Get all into one string.
f.each_line(nil) {|line| p line }
f.close

Вывод:

"First line\nSecond line\n\nFourth line\nFifth line\n"

f.rewind
# Get paragraphs (up to two line separators).
f.each_line('') {|line| p line }

Вывод:

"First line\nSecond line\n\n"
"Fourth line\nFifth line\n"

Только с целочисленным аргументом limit, ограничивает количество байтов в каждой строке; см. Предел строк:

f = File.new('t.txt')
f.each_line(8) {|line| p line }
f.close

Вывод:

"First li"
"ne\n"
"Second l"
"ine\n"
"\n"
"Fourth l"
"ine\n"
"Fifth li"
"ne\n"

С аргументами sep и limit, объединяет два поведения:

  • Вызывает блок с следующей строкой, определяемой разделителем строк sep;

  • Но возвращает не более байтов, чем разрешено пределом.

Необязательный ключевой аргумент chomp указывает, следует ли пропускать разделители строк:

f = File.new('t.txt')
f.each_line(chomp: true) {|line| p line }
f.close

Вывод:

"First line"
"Second line"
""
"Fourth line"
"Fifth line"

Возвращает Enumerator, если блок не задан.

IO#each — псевдоним для IO#each_line.

Также псевдоним: each_line
each_byte {|byte| ... } → self Показать исходный код
each_byte → перечислитель
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));
            rb_io_check_byte_readable(fptr);
            errno = 0;
        }
        READ_CHECK(fptr);
    } while (io_fillbuf(fptr) >= 0);
    return io;
}

Вызывает заданный блок с каждым байтом (0..255) в потоке; возвращает self. См. Байтовый IO.

f = File.new('t.rus')
a = []
f.each_byte {|b| a << b }
a # => [209, 130, 208, 181, 209, 129, 209, 130]
f.close

Возвращает Enumerator, если блок не задан.

Связанные: IO#each_char, IO#each_codepoint.

each_char {|c| ... } → self Показать исходный код
each_char → перечислитель
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;
}

Вызывает заданный блок с каждым символом в потоке; возвращает self. См. Символ IO.

f = File.new('t.rus')
a = []
f.each_char {|c| a << c.ord }
a # => [1090, 1077, 1089, 1090]
f.close

Возвращает Enumerator, если блок не задан.

Связанные: IO#each_byte, IO#each_codepoint.

each_codepoint {|c| ... } → self Показать исходный код
each_codepoint → перечислитель
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));
            rb_io_check_byte_readable(fptr);
        }
    }
    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)) {
            goto invalid;
        }
        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;
        }
        rb_io_check_byte_readable(fptr);
    }
    return io;

  invalid:
    rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
    UNREACHABLE_RETURN(Qundef);
}

Вызывает заданный блок с каждым кодовым значением в потоке; возвращает self:

f = File.new('t.rus')
a = []
f.each_codepoint {|c| a << c }
a # => [1090, 1077, 1089, 1090]
f.close

Возвращает Enumerator, если блок не задан.

Связанные: IO#each_byte, IO#each_char.

each_line(sep = $/, chomp: false) {|line| ... } → self
each_line(limit, chomp: false) {|line| ... } → self
each_line(sep, limit, chomp: false) {|line| ... } → self
each_line → перечислитель

Вызывает блок с каждой оставшейся строкой, прочитанной из потока; возвращает self. Ничего не делает, если уже достигнут конец потока; См. Строка IO.

Без аргументов читает строки, определяемые разделителем строк $/;

f = File.new('t.txt')
f.each_line {|line| p line }
f.each_line {|line| fail 'Cannot happen' }
f.close

Вывод:

"First line\n"
"Second line\n"
"\n"
"Fourth line\n"
"Fifth line\n"

Только с строковым аргументом sep, читает строки, определяемые разделителем строк sep; см. Разделитель строк:

f = File.new('t.txt')
f.each_line('li') {|line| p line }
f.close

Вывод:

"First li"
"ne\nSecond li"
"ne\n\nFourth li"
"ne\nFifth li"
"ne\n"

Два специальных значения для sep;

f = File.new('t.txt')
# Get all into one string.
f.each_line(nil) {|line| p line }
f.close

Вывод:

"First line\nSecond line\n\nFourth line\nFifth line\n"

f.rewind
# Get paragraphs (up to two line separators).
f.each_line('') {|line| p line }

Вывод:

"First line\nSecond line\n\n"
"Fourth line\nFifth line\n"

Только с целочисленным аргументом limit, ограничивает количество байтов в каждой строке; см. Предел строк:

f = File.new('t.txt')
f.each_line(8) {|line| p line }
f.close

Вывод:

"First li"
"ne\n"
"Second l"
"ine\n"
"\n"
"Fourth l"
"ine\n"
"Fifth li"
"ne\n"

С аргументами sep и limit, объединяет два поведения:

  • Вызывает блок с следующей строкой, определяемой разделителем строк sep;

  • Но возвращает не более байтов, чем разрешено пределом.

Необязательный ключевой аргумент chomp указывает, следует ли пропускать разделители строк:

f = File.new('t.txt')
f.each_line(chomp: true) {|line| p line }
f.close

Вывод:

"First line"
"Second line"
""
"Fourth line"
"Fifth line"

Возвращает Enumerator, если блок не задан.

IO#each — псевдоним для IO#each_line.

Псевдоним для: each
echo = flag Показать исходный код
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)) sys_fail_fptr(fptr);
    if (RTEST(f))
        set_echo(&t, NULL);
    else
        set_noecho(&t, NULL);
    if (!setattr(fd, &t)) sys_fail_fptr(fptr);
    return io;
}

Включает/отключает вывод эха. На некоторых платформах не все комбинации этих флагов и режимов raw/cooked могут быть валидными.

Для использования этого метода необходимо подключить ‘io/console’.

echo? → true или false Показать исходный код
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)) sys_fail_fptr(fptr);
    return echo_p(&t) ? Qtrue : Qfalse;
}

Возвращает true, если вывод эха включён.

Для использования этого метода необходимо подключить ‘io/console’.

eof → true или false Показать исходный код
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 RUBY_CRLF_ENVIRONMENT
    if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
        return RBOOL(eof(fptr->fd));;
    }
#endif
    return RBOOL(io_fillbuf(fptr) < 0);
}

Возвращает true, если поток находится в конце, false в противном случае; см. Положение:

f = File.open('t.txt')
f.eof           # => false
f.seek(0, :END) # => 0
f.eof           # => true
f.close

Вызывает исключение, если поток не открыт для чтения; см. Режимы доступа.

Если self является потоком, таким как канал или сокет, этот метод блокируется до тех пор, пока другой конец не отправит какие-либо данные или не закроется:

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

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

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

Обратите внимание, что этот метод считывает данные в буфер входного байта. Поэтому IO#sysread может вести себя не так, как вы ожидаете, с IO#eof?, если вы не вызовете IO#rewind сначала (что недоступно для некоторых потоков).

IO#eof? является псевдонимом для IO#eof.

Также алиасирован как: eof?
eof?()

Возвращает true, если поток находится в конце, false в противном случае; см. Положение:

f = File.open('t.txt')
f.eof           # => false
f.seek(0, :END) # => 0
f.eof           # => true
f.close

Вызывает исключение, если поток не открыт для чтения; см. Режимы доступа.

Если self является потоком, таким как канал или сокет, этот метод блокируется до тех пор, пока другой конец не отправит какие-либо данные или не закроется:

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

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

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

Обратите внимание, что этот метод считывает данные в буфер входного байта. Поэтому IO#sysread может вести себя не так, как вы ожидаете, с IO#eof?, если вы не вызовете IO#rewind сначала (что недоступно для некоторых потоков).

IO#eof? является псевдонимом для IO#eof.

Псевдоним для: eof
erase_line(p1) Показать исходный код
static VALUE
console_erase_line(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;
    int mode = mode_in_range(val, 2, "line erase");

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    if (!GetConsoleScreenBufferInfo(h, &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    w = winsize_col(&ws);
    switch (mode) {
      case 0:                   /* after cursor */
        w -= pos->X;
        break;
      case 1:                   /* before *and* cursor */
        w = pos->X + 1;
        pos->X = 0;
        break;
      case 2:                   /* entire line */
        pos->X = 0;
        break;
    }
    constat_clear(h, ws.wAttributes, w, *pos);
    return io;
}
erase_screen(p1) Показать исходный код
static VALUE
console_erase_screen(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;
    int mode = mode_in_range(val, 3, "screen erase");

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    if (!GetConsoleScreenBufferInfo(h, &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    w = winsize_col(&ws);
    switch (mode) {
      case 0:   /* erase after cursor */
        w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
        break;
      case 1:   /* erase before *and* cursor */
        w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
        pos->X = 0;
        pos->Y = ws.srWindow.Top;
        break;
      case 2:   /* erase entire screen */
        w = (w * winsize_row(&ws));
        pos->X = 0;
        pos->Y = ws.srWindow.Top;
        break;
      case 3:   /* erase entire screen */
        w = (w * ws.dwSize.Y);
        pos->X = 0;
        pos->Y = 0;
        break;
    }
    constat_clear(h, ws.wAttributes, w, *pos);
    return io;
}
IO#expect(pattern,timeout=9999999) → Массив Показать исходный код
IO#expect(pattern,timeout=9999999) { |result| ... } → nil
# File ext/pty/lib/expect.rb, line 33
def expect(pat,timeout=9999999)
  buf = ''.dup
  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)
    elsif !IO.select([self],nil,nil,timeout) or eof? then
      result = nil
      @unusedBuf = buf
      break
    else
      c = getc
    end
    buf << c
    if $expect_verbose
      STDOUT.print c
      STDOUT.flush
    end
    if mat=e_pat.match(buf) then
      result = [buf,*mat.captures]
      break
    end
  end
  if block_given? then
    yield result
  else
    return result
  end
  nil
end

Библиотека expect добавляет метод экземпляра IO#expect, который похож на расширение TCL expect.

Для использования этого метода необходимо подключить expect:

require 'expect'

Считывает из IO до тех пор, пока заданный pattern не совпадёт или не закончится timeout.

Возвращает массив считанного буфера, после которого следуют совпадения. Если задан блок, результат передаётся в блок, и возвращается nil.

При вызове без блока, он ждёт, пока входной данные, соответствующие заданному pattern будут получены из IO или пока не пройдёт заданное время таймаута. Массив возвращается, когда шаблон получен из IO. Первый элемент массива — это вся строка, полученная из IO до тех пор, пока шаблон не совпадёт, а следующие элементы указывают, какой шаблон сопоставился с якорем в регулярном выражении.

Необязательный параметр таймаута определяет общее время ожидания шаблона в секундах. Если таймаут истекает или находится eof, возвращается или передаётся nil. Однако буфер в сессии таймаута сохраняется для следующего вызова expect. Значение по умолчанию для таймаута составляет 9999999 секунд.

external_encoding → кодировка или nil Показать исходный код
static VALUE
rb_io_external_encoding(VALUE io)
{
    rb_io_t *fptr = RFILE(rb_io_taint_check(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));
}

Возвращает объект Encoding, который представляет кодировку потока, или nil если поток в режиме записи и кодировка не указана.

См. Кодировки.

fcntl(целочисленный_cmd, аргумент) → целое Показать исходный код
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);
}

Вызывает системный вызов Posix fcntl(2), который предоставляет механизм для выдачи команд низкого уровня для управления или запроса потока ввода-вывода с ориентацией на файлы. Аргументы и результаты зависят от платформы.

Если +аргумент — это число, его значение передаётся непосредственно; если это строка, она интерпретируется как двоичная последовательность байтов. (Array#pack может быть полезным способом построения этой строки.)

Не реализовано на всех платформах.

fdatasync → 0 Показать исходный код
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_on_write(fptr);

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

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

Немедленно записывает на диск все данные, буферизованные в потоке, через системный вызов ОС: fdatasync(2), если поддерживается, иначе через fsync(2), если поддерживается; в противном случае вызывает исключение.

fileno → целое Показать исходный код
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);
}

Возвращает целочисленный дескриптор файла для потока:

$stdin.fileno             # => 0
$stdout.fileno            # => 1
$stderr.fileno            # => 2
File.open('t.txt').fileno # => 10
f.close

IO#to_i является псевдонимом для IO#fileno.

Также алиасирован как: to_i
flush → self Показать исходный код
VALUE
rb_io_flush(VALUE io)
{
    return rb_io_flush_raw(io, 1);
}

Очищает данные, буферизованные в self в операционной системе (но не обязательно очищает данные, буферизованные в операционной системе):

$stdout.print 'no newline' # Not necessarily flushed.
$stdout.flush              # Flushed.
fsync → 0 Показать исходный код
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_on_write(fptr);
    if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
        rb_sys_fail_path(fptr->pathv);
    return INT2FIX(0);
}

Немедленно записывает на диск все данные, буферизованные в потоке, через системный вызов ОС fsync(2).

Обратите внимание на это различие:

  • IO#sync=: Гарантирует, что данные очищены из внутренних буферов потока, но не гарантирует, что операционная система фактически запишет данные на диск.

  • IO#fsync: Гарантирует, что данные очищены как из внутренних буферов, так и записаны на диск.

Вызывает исключение, если операционная система не поддерживает fsync(2).

getbyte → целое или nil Показать исходный код
VALUE
rb_io_getbyte(VALUE io)
{
    rb_io_t *fptr;
    int c;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    READ_CHECK(fptr);
    VALUE r_stdout = rb_ractor_stdout();
    if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
        rb_io_t *ofp;
        GetOpenFile(r_stdout, ofp);
        if (ofp->mode & FMODE_TTY) {
            rb_io_flush(r_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);
}

Считывает и возвращает следующий байт (в диапазоне 0..255) из потока; возвращает nil если уже в конце потока. См. Байтовый ввод-вывод.

f = File.open('t.txt')
f.getbyte # => 70
f.close
f = File.open('t.rus')
f.getbyte # => 209
f.close

Связанно с: IO#readbyte (может вызвать EOFError).

getc → символ или nil Показать исходный код
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);
}

Читает и возвращает следующую строку из 1 символа из потока; возвращает nil , если уже достигнут конец потока. См. Ввод-вывод символов.

f = File.open('t.txt')
f.getc     # => "F"
f.close
f = File.open('t.rus')
f.getc.ord # => 1090
f.close

Связанные: IO#readchar (может выбросить EOFError).

getch(min: nil, time: nil, intr: nil) → символ Показать исходный код
static VALUE
console_getch(int argc, VALUE *argv, VALUE io)
{
    rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
#ifndef _WIN32
    return ttymode(io, getc_call, io, set_rawmode, optp);
#else
    rb_io_t *fptr;
    VALUE str;
    wint_t c;
    int len;
    char buf[8];
    wint_t wbuf[2];
# ifndef HAVE_RB_IO_WAIT
    struct timeval *to = NULL, tv;
# else
    VALUE timeout = Qnil;
# endif

    GetOpenFile(io, fptr);
    if (optp) {
        if (optp->vtime) {
# ifndef HAVE_RB_IO_WAIT
            to = &tv;
# else
            struct timeval tv;
# endif
            tv.tv_sec = optp->vtime / 10;
            tv.tv_usec = (optp->vtime % 10) * 100000;
# ifdef HAVE_RB_IO_WAIT
            timeout = rb_fiber_scheduler_make_timeout(&tv);
# endif
        }
        switch (optp->vmin) {
          case 1: /* default */
            break;
          case 0: /* return nil when timed out */
            if (optp->vtime) break;
            /* fallthru */
          default:
            rb_warning("min option larger than 1 ignored");
        }
        if (optp->intr) {
# ifndef HAVE_RB_IO_WAIT
            int w = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, to);
            if (w < 0) rb_eof_error();
            if (!(w & RB_WAITFD_IN)) return Qnil;
# else
            VALUE result = rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
            if (!RTEST(result)) return Qnil;
# endif
        }
        else if (optp->vtime) {
            rb_warning("Non-zero vtime option ignored if intr flag is unset");
        }
    }
    len = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getch, wbuf, RUBY_UBF_IO, 0);
    switch (len) {
      case 0:
        return Qnil;
      case 2:
        buf[0] = (char)wbuf[0];
        c = wbuf[1];
        len = 1;
        do {
            buf[len++] = (unsigned char)c;
        } while ((c >>= CHAR_BIT) && len < (int)sizeof(buf));
        return rb_str_new(buf, len);
      default:
        c = wbuf[0];
        len = rb_uv_to_utf8(buf, c);
        str = rb_utf8_str_new(buf, len);
        return rb_str_conv_enc(str, NULL, rb_default_external_encoding());
    }
#endif
}

Читает и возвращает символ в сыром режиме.

См. IO#raw для получения подробностей о параметрах.

Для использования этого метода необходимо подключить ‘io/console’.

getpass(prompt=nil) → строка Показать исходный код
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);
}

Читает и возвращает строку без отображения ввода. Выводит prompt , если это не nil.

Символ новой строки, завершающий считанную строку, удаляется из возвращаемой строки, см. String#chomp!.

Для использования этого метода необходимо подключить ‘io/console’.

gets(sep = $/, chomp: false) → строка или nil Показать исходный код
gets(limit, chomp: false) → строка или nil
gets(sep, limit, chomp: false) → строка или nil
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;
}

Читает и возвращает строку из потока; присваивает возвращаемое значение $_. См. Ввод-вывод строк.

Без аргументов, возвращает следующую строку, определяемую разделителем строк $/, или nil , если нет:

f = File.open('t.txt')
f.gets # => "First line\n"
$_     # => "First line\n"
f.gets # => "\n"
f.gets # => "Fourth line\n"
f.gets # => "Fifth line\n"
f.gets # => nil
f.close

С аргументом строкой sep , возвращает следующую строку, определяемую разделителем строк sep, или nil , если нет; см. Разделитель строк:

f = File.new('t.txt')
f.gets('l')   # => "First l"
f.gets('li')  # => "ine\nSecond li"
f.gets('lin') # => "ne\n\nFourth lin"
f.gets        # => "e\n"
f.close

Два специальных значения для sep учитываются:

f = File.new('t.txt')
# Get all.
f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.rewind
# Get paragraph (up to two line separators).
f.gets('')  # => "First line\nSecond line\n\n"
f.close

С целочисленным аргументом limit , ограничивает количество байтов в строке; см. Предел строки:

# No more than one line.
File.open('t.txt') {|f| f.gets(10) } # => "First line"
File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
File.open('t.txt') {|f| f.gets(12) } # => "First line\n"

С аргументами sep и limit , объединяет оба поведения:

  • Возвращает следующую строку, определяемую разделителем строк sep, или nil , если нет.

  • Но возвращает не более байтов, чем разрешено пределом.

Необязательный ключевой аргумент chomp указывает, должны ли разделители строк быть опущены:

f = File.open('t.txt')
# Chomp the lines.
f.gets(chomp: true) # => "First line"
f.gets(chomp: true) # => "Second line"
f.gets(chomp: true) # => ""
f.gets(chomp: true) # => "Fourth line"
f.gets(chomp: true) # => "Fifth line"
f.gets(chomp: true) # => nil
f.close
goto(p1, p2) Показать исходный код
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
    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;
}
goto_column(p1) Показать исходный код
static VALUE
console_goto_column(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    if (!GetConsoleScreenBufferInfo(h, &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    pos->X = NUM2INT(val);
    if (!SetConsoleCursorPosition(h, *pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    return io;
}
iflush Показать исходный код
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)) sys_fail_fptr(fptr);
#endif
    (void)fd;
    return io;
}

Очищает буфер ввода в ядре.

Для использования этого метода необходимо подключить ‘io/console’.

inspect → строка Показать исходный код
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, ">");
}

Возвращает строковое представление self:

f = File.open('t.txt')
f.inspect # => "#<File:t.txt>"
f.close
internal_encoding → кодировка или nil Показать исходный код
static VALUE
rb_io_internal_encoding(VALUE io)
{
    rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;

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

Возвращает объект Encoding, представляющий кодировку внутренней строки, если указана конвертация, или nil в противном случае.

См. Кодировки.

ioctl(integer_cmd, argument) → целое число Показать исходный код
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);
}

Вызывает системный вызов Posix ioctl(2), который выполняет низкоуровневую команду для устройства ввода-вывода.

Выполняет низкоуровневую команду для устройства ввода-вывода. Аргументы и возвращаемое значение зависят от платформы. Эффект вызова зависит от платформы.

Если аргумент argument является целым числом, он передаётся непосредственно; если строкой, интерпретируется как двоичная последовательность байтов.

Не реализовано на всех платформах.

ioflush Показать исходный код
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)) sys_fail_fptr(fptr);
        if (tcflush(fd2, TCOFLUSH)) sys_fail_fptr(fptr);
    }
    else {
        if (tcflush(fd1, TCIOFLUSH)) sys_fail_fptr(fptr);
    }
#endif
    return io;
}

Очищает буферы ввода и вывода в ядре.

Для использования этого метода необходимо подключить ‘io/console’.

isatty → true или false Показать исходный код
static VALUE
rb_io_isatty(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    return RBOOL(isatty(fptr->fd) != 0);
}

Возвращает true , если поток связан с терминальным устройством (tty), false в противном случае:

f = File.new('t.txt').isatty    #=> false
f.close
f = File.new('/dev/tty').isatty #=> true
f.close

IO#tty? является псевдонимом для IO#isatty.

Также алиас: tty?
lineno → целое число Показать исходный код
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 = целое число → целое число Показать исходный код
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;
}

Устанавливает и возвращает номер строки для потока; см. Номер строки.

noecho {|io| } Показать исходный код
static VALUE
console_noecho(VALUE io)
{
    return ttymode(io, rb_yield, io, set_noecho, NULL);
}

Выполняет self с отключением отображения ввода.

STDIN.noecho(&:gets)

будет читать и возвращать строку без отображения ввода.

Для использования этого метода необходимо подключить ‘io/console’.

nonblock {|io| } → объект
nonblock(boolean) {|io| } → объект
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 = get_fcntl_flags(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);
}

Выполняет self в режиме без ожидания.

Когда false задан в качестве аргумента, self выполняется в режиме ожидания. Исходный режим восстанавливается после выполнения блока.

END_OF_DOCUMENT_MARKER
nonblock = boolean → boolean Показать исходный код
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, get_fcntl_flags(fptr->fd), RTEST(nb));
    return io;
}

Включает режим без ожидания для потока, если установлено значение true, и режим ожидания, если установлено значение false.

Этот метод устанавливает или сбрасывает флаг O_NONBLOCK для дескриптора файла в ios.

Поведение большинства методов IO не зависит от этого флага, потому что они повторяют системные вызовы для завершения задачи после EAGAIN и частичного чтения/записи. (Исключение составляет IO#syswrite, который не повторяет попытки.)

Этот метод может быть использован для сброса режима без ожидания для стандартного ввода-вывода. Поскольку неблокирующие методы (read_nonblock и т.д.) устанавливают режим без ожидания, но не сбрасывают его, этот метод можно использовать следующим образом.

END { STDOUT.nonblock = false }
STDOUT.write_nonblock("foo")

Поскольку флаг общий для процессов, и многие команды, не написанные на Ruby, не ожидают стандартного ввода-вывода в режиме без ожидания, было бы безопасно сбросить флаг перед завершением программы на Ruby.

Например, следующая программа на Ruby оставляет STDIN/STDOUT/STDER в режиме без ожидания. (STDIN, STDOUT и STDERR подключены к терминалу. Поэтому приведение одного из них в режим без ожидания влияет на остальные два.) Таким образом, команда cat пытается прочитать стандартный ввод, и это вызывает ошибку «Ресурс временно недоступен» (EAGAIN).

% ruby -e '
STDOUT.write_nonblock("foo\n")'; cat
foo
cat: -: Resource temporarily unavailable

Сброс флага приводит к нормальному поведению команды cat. (Команда cat ожидает ввода со стандартного ввода.)

% ruby -rio/nonblock -e '
END { STDOUT.nonblock = false }
STDOUT.write_nonblock("foo")
'; cat
foo
nonblock? → boolean Показать исходный код
static VALUE
rb_io_nonblock_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (get_fcntl_flags(fptr->fd) & O_NONBLOCK)
        return Qtrue;
    return Qfalse;
}

Возвращает true, если объект IO находится в режиме без ожидания.

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);
}

Возвращает количество байтов, которые могут быть прочитаны без ожидания. Возвращает ноль, если нет доступной информации.

Для использования этого метода необходимо подключить ‘io/wait’.

oflush Показать исходный код
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)) sys_fail_fptr(fptr);
#endif
    (void)fd;
    return io;
}

Очищает буфер вывода в ядре.

Для использования этого метода необходимо подключить ‘io/console’.

path → string or nil Показать исходный код
static VALUE
rb_io_path(VALUE io)
{
    rb_io_t *fptr = RFILE(io)->fptr;

    if (!fptr)
        return Qnil;

    return rb_obj_dup(fptr->pathv);
}

Возвращает путь, связанный с IO, или nil, если с IO не связан никакой путь. Не гарантируется, что путь существует в файловой системе.

$stdin.path # => "<STDIN>"

File.open("testfile") {|f| f.path} # => "testfile"
Также алиас: to_path
pathconf(p1) Показать исходный код
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);
}

Возвращает переменную конфигурации имени пути, используя fpathconf().

name должен быть константой в Etc, начинающейся с PC_.

Возвращаемое значение — целое число или nil. nil означает неопределённый предел. (fpathconf() возвращает -1, но errno не устанавливается.)

require 'etc'
IO.pipe {|r, w|
  p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
}
pid → integer or nil Показать исходный код
static VALUE
rb_io_pid(VALUE io)
{
    rb_io_t *fptr;

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

Возвращает идентификатор процесса дочернего процесса, связанного с потоком, который был задан IO#popen, или nil, если поток не был создан с помощью IO#popen:

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

Вывод:

In child, pid is 26209
In parent, child pid is 26209
pos()

Возвращает текущую позицию (в байтах) в self (см. Позиция):

f = File.open('t.txt')
f.tell # => 0
f.gets # => "First line\n"
f.tell # => 12
f.close

Связанные: IO#pos=, IO#seek.

IO#pos является алиасом для IO#tell.

Алиас для: tell
pos = new_position → new_position Показать исходный код
static VALUE
rb_io_set_pos(VALUE io, VALUE offset)
{
    rb_io_t *fptr;
    rb_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);
}

Перемещает указатель на заданную new_position (в байтах); см. Позиция:

f = File.open('t.txt')
f.tell     # => 0
f.pos = 20 # => 20
f.tell     # => 20
f.close

Связанные: IO#seek, IO#tell.

pread(maxlen, offset) → string Показать исходный код
pread(maxlen, offset, out_string) → string
static VALUE
rb_io_pread(int argc, VALUE *argv, VALUE io)
{
    VALUE len, offset, str;
    rb_io_t *fptr;
    ssize_t n;
    struct prdwr_internal_arg arg;
    int shrinkable;

    rb_scan_args(argc, argv, "21", &len, &offset, &str);
    arg.count = NUM2SIZET(len);
    arg.offset = NUM2OFFT(offset);

    shrinkable = io_setstrbuf(&str, (long)arg.count);
    if (arg.count == 0) return str;
    arg.buf = RSTRING_PTR(str);

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

    arg.fd = fptr->fd;
    rb_io_check_closed(fptr);

    rb_str_locktmp(str);
    n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);

    if (n < 0) {
        rb_sys_fail_path(fptr->pathv);
    }
    io_set_read_length(str, n, shrinkable);
    if (n == 0 && arg.count > 0) {
        rb_eof_error();
    }

    return str;
}

Ведет себя как IO#readpartial, за исключением:

  • Читает по заданной offset (в байтах).

  • Игнорирует и не изменяет позицию потока (см. Позицию).

  • Обойдены любые буферизации в пользовательском пространстве потока.

Поскольку этот метод не затрагивает состояние потока (в частности, его позицию), pread позволяет нескольким потокам и процессам использовать один и тот же объект IO для чтения по различным смещениям.

f = File.open('t.txt')
f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.pos  # => 52
# Read 12 bytes at offset 0.
f.pread(12, 0) # => "First line\n"
# Read 9 bytes at offset 8.
f.pread(9, 8)  # => "ne\nSecon"
f.close

Недоступно на некоторых платформах.

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(*objects) → nil Показать исходный код
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
printf(format_string, *objects) → nil Показать исходный код
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, см. Спецификации формата.

putc(object) → object Показать исходный код
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
END_OF_DOCUMENT_MARKER
puts(*objects) → nil Show source
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
    int i, n;
    VALUE line, args[2];

    /* 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:
        n = 0;
        args[n++] = line;
        if (RSTRING_LEN(line) == 0 ||
            !rb_str_end_with_asciichar(line, '\n')) {
            args[n++] = rb_default_rs;
        }
        rb_io_writev(out, n, args);
    }

    return Qnil;
}

Записывает заданные objects в поток, который должен быть открыт для записи; возвращает nil.\ Записывает новую строку после каждого объекта, который не заканчивается на последовательность новой строки. Если вызывается без аргументов, записывает новую строку. См. Line IO.

Обратите внимание, что каждая добавляемая новая строка — это символ "\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"
pwrite(object, offset) → integer Show source
static VALUE
rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
{
    rb_io_t *fptr;
    ssize_t n;
    struct prdwr_internal_arg arg;
    VALUE tmp;

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

    arg.offset = NUM2OFFT(offset);

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    rb_io_check_writable(fptr);
    arg.fd = fptr->fd;

    tmp = rb_str_tmp_frozen_acquire(str);
    arg.buf = RSTRING_PTR(tmp);
    arg.count = (size_t)RSTRING_LEN(tmp);

    n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
    if (n < 0) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return SSIZET2NUM(n);
}

Ведет себя как IO#write, за исключением того, что он:

  • Записывает в заданный offset (в байтах).

  • Игнорирует и не изменяет положение потока (см. Position).

  • Обходит любое буферизацию пользовательского пространства в потоке.

Поскольку этот метод не изменяет состояние потока (в частности, его положение), pwrite позволяет нескольким потокам и процессам использовать один и тот же объект IO для записи в разных смещениях.

f = File.open('t.tmp', 'w+')
# Write 6 bytes at offset 3.
f.pwrite('ABCDEF', 3) # => 6
f.rewind
f.read # => "\u0000\u0000\u0000ABCDEF"
f.close

Недоступно на некоторых платформах.

raw(min: nil, time: nil, intr: nil) {|io| } Show source
static VALUE
console_raw(int argc, VALUE *argv, VALUE io)
{
    rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
    return ttymode(io, rb_yield, io, set_rawmode, optp);
}

Передает self в сыром режиме и возвращает результат блока.

STDIN.raw(&:gets)

будет читать и возвращать строку без эха и редактирования строки.

Параметр min указывает минимальное количество байтов, которые должны быть получены при выполнении операции чтения. (по умолчанию: 1)

Параметр time указывает время ожидания в секундах с точностью до 1/10 секунды. (по умолчанию: 0)

Если параметр intr равен true, включает специальные символы break, interrupt, quit и suspend.

Дополнительные сведения см. на странице руководства termios.

Для использования этого метода необходимо require ‘io/console’.

raw!(min: nil, time: nil, intr: nil) → io Show source
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, 0, 0, &opts);

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

Включает сырой режим и возвращает io.

Если необходимо вернуть режим терминала, используйте io.raw { ... }.

См. IO#raw для получения подробной информации о параметрах.

Для использования этого метода необходимо require ‘io/console’.

read(maxlen = nil, out_string = nil) → new_string, out_string, or nil Show source
static VALUE
io_read(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    long n, len;
    VALUE length, str;
    int shrinkable;
#if RUBY_CRLF_ENVIRONMENT
    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);
    }

    shrinkable = io_setstrbuf(&str,len);

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

    READ_CHECK(fptr);
#if RUBY_CRLF_ENVIRONMENT
    previous_mode = set_binary_mode_with_seek_cur(fptr);
#endif
    n = io_fread(str, 0, len, fptr);
    io_set_read_length(str, n, shrinkable);
#if RUBY_CRLF_ENVIRONMENT
    if (previous_mode == O_TEXT) {
        setmode(fptr->fd, O_TEXT);
    }
#endif
    if (n == 0) return Qnil;

    return str;
}

Читает байты из потока; поток должен быть открыт для чтения (см. Access Modes):

  • Если maxlen равно nil, считывает все байты, используя режим данных потока.

  • В противном случае считывает до maxlen байтов в двоичном режиме.

Возвращает строку (новую строку или заданную out_string) содержащую считанные байты. Кодировка строки зависит от maxLen и out_string;

  • maxlen равно nil: используется внутренняя кодировка self (независимо от того, был ли задан out_string).

  • maxlen не nil:

    • out_string задан: кодировка out_string не изменена.

    • out_string не задан: используется ASCII-8BIT.

Без аргумента out_string

Когда аргумент out_string опущен, возвращаемое значение — новая строка:

f = File.new('t.txt')
f.read
# => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.rewind
f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
f.read(30) # => "rth line\r\nFifth line\r\n"
f.read(30) # => nil
f.close

Если maxlen равно нулю, возвращает пустую строку.

С аргументом out_string

Когда аргумент out_string задан, возвращаемое значение — out_string, содержимое которого заменяется:

f = File.new('t.txt')
s = 'foo'      # => "foo"
f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
s              # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.rewind
s = 'bar'
f.read(30, s)  # => "First line\r\nSecond line\r\n\r\nFou"
s              # => "First line\r\nSecond line\r\n\r\nFou"
s = 'baz'
f.read(30, s)  # => "rth line\r\nFifth line\r\n"
s              # => "rth line\r\nFifth line\r\n"
s = 'bat'
f.read(30, s)  # => nil
s              # => ""
f.close

Обратите внимание, что этот метод работает как функция fread() в C. Это означает, что он пытается вызывать системные вызовы read(2) для чтения данных с указанным maxlen (или до EOF).

Это поведение сохраняется даже если поток находится в неблокирующем режиме. (Этот метод нечувствителен к неблокирующему флагу, как другие методы.)

Если вам нужно поведение, подобное одному системному вызову read(2), рассмотрите readpartial, read_nonblock и sysread.

Связанное: IO#write.

read_nonblock(maxlen [, options]) → string Show source
read_nonblock(maxlen, outbuf [, options]) → outbuf
# File io.rb, line 62
def read_nonblock(len, buf = nil, exception: true)
  Primitive.io_read_nonblock(len, buf, exception)
end

Считывает не более maxlen байтов из ios с помощью системного вызова read(2) после установки O_NONBLOCK для базового файлового дескриптора.

Если присутствует необязательный аргумент 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 вызывает EOFError в конце файла.

На некоторых платформах, таких как Windows, неблокирующий режим не поддерживается для объектов IO, отличных от сокетов. В таких случаях будет возбуждено Errno::EBADF.

Если буфер чтения байтов не пуст, read_nonblock считывает из буфера как readpartial. В этом случае системный вызов read(2) не вызывается.

Когда read_nonblock вызывает исключение типа IO::WaitReadable, read_nonblock не следует вызывать до тех пор, пока io не станет доступен для чтения во избежание зацикливания. Это можно сделать следующим образом.

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

Хотя IO#read_nonblock не вызывает IO::WaitWritable. OpenSSL::Buffering#read_nonblock может вызвать IO::WaitWritable. Если IO и SSL должны использоваться полиморфно, IO::WaitWritable также следует обрабатывать. См. документацию OpenSSL::Buffering#read_nonblock для примера кода.

Обратите внимание, что этот метод идентичен readpartial, за исключением того, что установлен неблокирующий флаг.

Указав аргумент ключевого слова exception для false, вы можете указать, что read_nonblock не должен вызывать исключение IO::WaitReadable, а вместо этого возвращать символ :wait_readable. В конце файла он вернет nil, вместо того чтобы вызывать EOFError.

readbyte → integer Show source
static VALUE
rb_io_readbyte(VALUE io)
{
    VALUE c = rb_io_getbyte(io);

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

Считывает и возвращает следующий байт (в диапазоне 0..255) из потока; вызывает EOFError, если уже находится в конце потока. См. Byte IO.

f = File.open('t.txt')
f.readbyte # => 70
f.close
f = File.open('t.rus')
f.readbyte # => 209
f.close

Связанное: IO#getbyte (не будет вызывать EOFError).

readchar → string Show source
static VALUE
rb_io_readchar(VALUE io)
{
    VALUE c = rb_io_getc(io);

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

Считывает и возвращает следующую строку из 1 символа из потока; вызывает EOFError, если уже находится в конце потока. См. Character IO.

f = File.open('t.txt')
f.readchar     # => "F"
f.close
f = File.open('t.rus')
f.readchar.ord # => 1090
f.close

Связанное: IO#getc (не будет вызывать EOFError).

readline(sep = $/, chomp: false) → string Показать исходный код
readline(limit, chomp: false) → string
readline(sep, limit, chomp: false) → string
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;
}

Считывает строку так же, как и IO#gets, но вызывает исключение EOFError, если уже достигнут конец потока.

Необязательный ключевой аргумент chomp указывает, нужно ли опускать разделители строк.

readlines(sep = $/, chomp: false) → array Показать исходный код
readlines(limit, chomp: false) → array
readlines(sep, limit, chomp: false) → array
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);
}

Считывает и возвращает все оставшиеся строки из потока; не изменяет $_. См. Потоки строк.

Без аргументов возвращает строки, определяемые разделителем строк $/, или nil в случае отсутствия:

f = File.new('t.txt')
f.readlines
# => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
f.readlines # => []
f.close

С единственным строковым аргументом sep возвращает строки, определяемые разделителем строк sep, или nil в случае отсутствия; см. Разделитель строк:

f = File.new('t.txt')
f.readlines('li')
# => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
f.close

Два специальных значения для sep учитываются:

f = File.new('t.txt')
# Get all into one string.
f.readlines(nil)
# => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
# Get paragraphs (up to two line separators).
f.rewind
f.readlines('')
# => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
f.close

С единственным целочисленным аргументом limit ограничивает количество байтов в каждой строке; см. Ограничение строк:

f = File.new('t.txt')
f.readlines(8)
# => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
f.close

С аргументами sep и limit объединяет оба поведения:

  • Возвращает строки, определяемые разделителем строк sep.

  • Но не возвращает более байтов в строке, чем разрешено лимитом.

Необязательный ключевой аргумент chomp указывает, нужно ли опускать разделители строк:

f = File.new('t.txt')
f.readlines(chomp: true)
# => ["First line", "Second line", "", "Fourth line", "Fifth line"]
f.close
readpartial(maxlen) → string Показать исходный код
readpartial(maxlen, out_string) → out_string
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;
}

Считывает до maxlen байтов из потока; возвращает строку (либо новую строку, либо заданную out_string). Ее кодировка:

  • Неизменная кодировка out_string, если out_string задана.

  • ASCII-8BIT в противном случае.

  • Содержит maxlen байтов из потока, если доступны.

  • В противном случае содержит все доступные байты, если таковые имеются.

  • В противном случае является пустой строкой.

С одним целым положительным аргументом maxlen возвращает новую строку:

f = File.new('t.txt')
f.readpartial(20) # => "First line\nSecond l"
f.readpartial(20) # => "ine\n\nFourth line\n"
f.readpartial(20) # => "Fifth line\n"
f.readpartial(20) # Raises EOFError.
f.close

С аргументами maxlen и строковым аргументом out_string возвращает изменённую out_string:

f = File.new('t.txt')
s = 'foo'
f.readpartial(20, s) # => "First line\nSecond l"
s = 'bar'
f.readpartial(0, s)  # => ""
f.close

Этот метод полезен для потоков, таких как пайпы, сокеты или терминалы. Он блокируется только тогда, когда данные немедленно недоступны. Это означает, что он блокируется только тогда, когда все из следующего верно:

  • Буфер байтов в потоке пуст.

  • Содержание потока пусто.

  • Поток не находится в конце файла.

При блокировке метод ожидает либо дополнительных данных, либо конца файла:

  • Если считывается больше данных, метод возвращает данные.

  • Если достигнут конец файла, метод вызывает исключение EOFError.

При отсутствии блокировки метод реагирует немедленно:

  • Возвращает данные из буфера, если таковые имеются.

  • В противном случае возвращает данные из потока, если таковые имеются.

  • В противном случае вызывает исключение EOFError, если поток достиг конца файла.

Обратите внимание, что этот метод похож на sysread. Различия:

  • Если буфер байтов не пуст, считывается из буфера байтов, а не «sysread для буферизованного IO (IOError)».

  • Он не вызывает Errno::EWOULDBLOCK и Errno::EINTR. При встрече readpartial с EWOULDBLOCK и EINTR вызовом read, readpartial повторно пытается выполнить системный вызов.

Последнее означает, что readpartial нечувствителен к флагам без блокировки. Он блокируется в ситуации, когда IO#sysread вызывает Errno::EWOULDBLOCK так, как если бы fd был в режиме блокировки.

Примеры:

#                        # Returned      Buffer Content    Pipe Content
r, w = IO.pipe           #
w << 'abc'               #               ""                "abc".
r.readpartial(4096)      # => "abc"      ""                ""
r.readpartial(4096)      # (Blocks because buffer and pipe are empty.)

#                        # Returned      Buffer Content    Pipe Content
r, w = IO.pipe           #
w << 'abc'               #               ""                "abc"
w.close                  #               ""                "abc" EOF
r.readpartial(4096)      # => "abc"      ""                 EOF
r.readpartial(4096)      # raises EOFError

#                        # Returned      Buffer Content    Pipe Content
r, w = IO.pipe           #
w << "abc\ndef\n"        #               ""                "abc\ndef\n"
r.gets                   # => "abc\n"    "def\n"           ""
w << "ghi\n"             #               "def\n"           "ghi\n"
r.readpartial(4096)      # => "def\n"    ""                "ghi\n"
r.readpartial(4096)      # => "ghi\n"    ""                ""
ready? → truthy or falsy Показать исходный код
static VALUE
io_ready_p(VALUE io)
{
    rb_io_t *fptr;
#ifndef HAVE_RB_IO_WAIT
    struct timeval tv = {0, 0};
#endif

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    if (rb_io_read_pending(fptr)) return Qtrue;

#ifndef HAVE_RB_IO_WAIT
    return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
#else
    return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
#endif
}

Возвращает значение истины, если данные доступны без блокировки, или ложное значение.

Для использования этого метода необходимо потребовать 'io/wait'.

reopen(other_io) → self Показать исходный код
reopen(path, mode = 'r', **opts) → self
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_on_write(fptr);
    }
    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;
}

Переустанавливает поток связи с другим потоком, который может быть другого класса. Этот метод может быть использован для перенаправления существующего потока в новое место назначения.

С аргументом other_io заданным, переустанавливает связь с этим потоком:

# Redirect $stdin from a file.
f = File.open('t.txt')
$stdin.reopen(f)
f.close

# Redirect $stdout to a file.
f = File.open('t.tmp', 'w')
$stdout.reopen(f)
f.close

С аргументом path заданным, переустанавливает связь с новым потоком для указанного пути к файлу:

$stdin.reopen('t.txt')
$stdout.reopen('t.tmp', 'w')

Необязательные ключевые аргументы opts задают:

  • Параметры открытия.

  • Параметры кодировки.

rewind → 0 Показать исходный код
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);
}

Перемещает поток в начало, устанавливая позицию и номер строки в ноль; см. Позиция и Номер строки:

f = File.open('t.txt')
f.tell     # => 0
f.lineno   # => 0
f.gets     # => "First line\n"
f.tell     # => 12
f.lineno   # => 1
f.rewind   # => 0
f.tell     # => 0
f.lineno   # => 0
f.close

Обратите внимание, что этот метод не может быть использован с потоками, такими как пайпы, терминалы и сокеты.

scroll_backward(p1) Показать исходный код
static VALUE
console_scroll_backward(VALUE io, VALUE val)
{
    return console_scroll(io, -NUM2INT(val));
}
scroll_forward(p1) Показать исходный код
static VALUE
console_scroll_forward(VALUE io, VALUE val)
{
    return console_scroll(io, +NUM2INT(val));
}
seek(offset, whence = IO::SEEK_SET) → 0 Показать исходный код
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);
}

Перемещает указатель на позицию, заданную целым числом offset (см. Позиция) и константой whence, которая может быть одной из:

  • :CUR или IO::SEEK_CUR: Перемещает поток на текущую позицию плюс заданное значение offset:

    f = File.open('t.txt')
    f.tell            # => 0
    f.seek(20, :CUR)  # => 0
    f.tell            # => 20
    f.seek(-10, :CUR) # => 0
    f.tell            # => 10
    f.close
    
  • :END или IO::SEEK_END: Перемещает поток на конец плюс заданное значение offset:

    f = File.open('t.txt')
    f.tell            # => 0
    f.seek(0, :END)   # => 0  # Repositions to stream end.
    f.tell            # => 52
    f.seek(-20, :END) # => 0
    f.tell            # => 32
    f.seek(-40, :END) # => 0
    f.tell            # => 12
    f.close
    
  • :SET или IO:SEEK_SET: Перемещает поток на заданную offset:

    f = File.open('t.txt')
    f.tell            # => 0
    f.seek(20, :SET) # => 0
    f.tell           # => 20
    f.seek(40, :SET) # => 0
    f.tell           # => 40
    f.close
    

Связанные: IO#pos=, IO#tell.

set_encoding(ext_enc) → self Показать исходный код
set_encoding(ext_enc, int_enc, **enc_opts) → self
set_encoding('ext_enc:int_enc', **enc_opts) → self
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 forward(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;
}

См. Кодировки.

Аргумент ext_enc, если задан, должен быть объектом Encoding; он назначается как кодировка для потока.

Аргумент int_enc, если задан, должен быть объектом Encoding; он назначается как кодировка для внутренней строки.

Аргумент 'ext_enc:int_enc', если задан, это строка, содержащая два разделенных двоеточием имени кодировок; соответствующие объекты Encoding назначаются как внешняя и внутренняя кодировки для потока.

Необязательные ключевые аргументы enc_opts задают параметры кодировки.

set_encoding_by_bom → encoding или nil Показать исходный код
static VALUE
rb_io_set_encoding_by_bom(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (!(fptr->mode & FMODE_BINMODE)) {
        rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
    }
    if (fptr->encs.enc2) {
        rb_raise(rb_eArgError, "encoding conversion is set");
    }
    else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
        rb_raise(rb_eArgError, "encoding is set to %s already",
                 rb_enc_name(fptr->encs.enc));
    }
    if (!io_set_encoding_by_bom(io)) return Qnil;
    return rb_enc_from_encoding(fptr->encs.enc);
}

Если поток начинается с BOM (маркер порядка байтов), потребляет BOM и устанавливает кодировку внешнего потока соответственно; возвращает результирующую кодировку, если найдена, или nil в противном случае:

File.write('t.tmp', "\u{FEFF}abc")
io = File.open('t.tmp', 'rb')
io.set_encoding_by_bom # => #<Encoding:UTF-8>
io.close

File.write('t.tmp', 'abc')
io = File.open('t.tmp', 'rb')
io.set_encoding_by_bom # => nil
io.close

Вызывает исключение, если поток не в binmode или его кодировка уже установлена.

stat → stat Показать исходный код
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);
}

Возвращает информацию о статусе 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
sync → true или false Показать исходный код
static VALUE
rb_io_sync(VALUE io)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    return RBOOL(fptr->mode & FMODE_SYNC);
}

Возвращает текущий режим синхронизации потока. Когда режим синхронизации true, весь вывод немедленно отправляется в операционную систему и не буферизуется Ruby. См. также fsync.

f = File.open('t.tmp', 'w')
f.sync # => false
f.sync = true
f.sync # => true
f.close
sync = boolean → boolean Показать исходный код
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;
}

Устанавливает режим sync для потока на заданное значение; возвращает заданное значение.

Значения для режима синхронизации:

  • true: Весь вывод немедленно отправляется в операционную систему и не буферизуется внутри.

  • false: Вывод может буферизоваться внутри.

Пример;

f = File.open('t.tmp', 'w')
f.sync # => false
f.sync = true
f.sync # => true
f.close

Связанно с: IO#fsync.

sysread(maxlen) → строка Показать исходный код
sysread(maxlen, out_string) → строка
static VALUE
rb_io_sysread(int argc, VALUE *argv, VALUE io)
{
    VALUE len, str;
    rb_io_t *fptr;
    long n, ilen;
    struct io_internal_read_struct iis;
    int shrinkable;

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

    shrinkable = 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");
    }

    rb_io_check_closed(fptr);

    io_setstrbuf(&str, ilen);
    iis.th = rb_thread_current();
    iis.fptr = fptr;
    iis.nonblock = 0;
    iis.fd = fptr->fd;
    iis.buf = RSTRING_PTR(str);
    iis.capa = ilen;
    iis.timeout = NULL;
    n = io_read_memory_locktmp(str, &iis);

    if (n < 0) {
        rb_sys_fail_path(fptr->pathv);
    }

    io_set_read_length(str, n, shrinkable);

    if (n == 0 && ilen > 0) {
        rb_eof_error();
    }

    return str;
}

Ведет себя как IO#readpartial, за исключением того, что использует функции низкого уровня системы.

Этот метод не следует использовать с другими методами чтения потоков.

sysseek(offset, whence = IO::SEEK_SET) → целое число Показать исходный код
static VALUE
rb_io_sysseek(int argc, VALUE *argv, VALUE io)
{
    VALUE offset, ptrname;
    int whence = SEEK_SET;
    rb_io_t *fptr;
    rb_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 < 0 && errno) rb_sys_fail_path(fptr->pathv);

    return OFFT2NUM(pos);
}

Ведет себя как IO#seek, за исключением того, что:

  • Использует функции низкого уровня системы.

  • Возвращает новую позицию.

syswrite(object) → целое число Показать исходный код
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_io_write_memory(fptr, ptr, len);
    if (n < 0) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return LONG2FIX(n);
}

Записывает указанный object в себя, который должен быть открыт для записи (см. режимы); возвращает количество записанных байтов. Если object не является строкой, он преобразуется с помощью метода to_s:

f = File.new('t.tmp', 'w')
f.syswrite('foo') # => 3
f.syswrite(30)    # => 2
f.syswrite(:foo)  # => 3
f.close

Этот метод не следует использовать с другими методами записи потоков.

tell → целое число Показать исходный код
static VALUE
rb_io_tell(VALUE io)
{
    rb_io_t *fptr;
    rb_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);
}

Возвращает текущую позицию (в байтах) в self (см. Позиция):

f = File.open('t.txt')
f.tell # => 0
f.gets # => "First line\n"
f.tell # => 12
f.close

Связанно с: IO#pos=, IO#seek.

IO#pos — псевдоним для IO#tell.

Также алиас: pos
timeout → продолжительность или nil Показать исходный код
VALUE
rb_io_timeout(VALUE self)
{
    rb_io_t *fptr = rb_io_get_fptr(self);

    return fptr->timeout;
}

Получить внутреннюю продолжительность таймаута или nil, если он не был установлен.

timeout = продолжительность → продолжительность Показать исходный код
timeout = nil → nil
VALUE
rb_io_set_timeout(VALUE self, VALUE timeout)
{
    // Validate it:
    if (RTEST(timeout)) {
        rb_time_interval(timeout);
    }

    rb_io_t *fptr = rb_io_get_fptr(self);

    fptr->timeout = timeout;

    return self;
}

Set внутренний таймаут на указанную продолжительность или nil. Таймаут применяется ко всем блокирующим операциям, где это возможно.

Это влияет на следующие методы (но не только): gets, puts, read, write, wait_readable и wait_writable. Это также влияет на блокирующие операции сокетов, такие как Socket#accept и Socket#connect.

Некоторые операции, такие как File#open и IO#close, на таймаут не влияют. Таймаут во время операции записи может оставить IO в несогласованном состоянии, например, данные были частично записаны. В целом, таймаут — это крайняя мера для предотвращения зависания приложения при медленных операциях ввода-вывода, таких как те, которые происходят во время атаки slowloris.

to_i()

Возвращает целое число дескриптора файла для потока:

$stdin.fileno             # => 0
$stdout.fileno            # => 1
$stderr.fileno            # => 2
File.open('t.txt').fileno # => 10
f.close

IO#to_i — псевдоним для IO#fileno.

Псевдоним для: fileno
to_io → self Показать исходный код
static VALUE
rb_io_to_io(VALUE io)
{
    return io;
}

Возвращает self.

to_path()

Возвращает путь, связанный с IO, или nil если с IO нет связанного пути. Гарантируется, что путь существует в файловой системе.

$stdin.path # => "<STDIN>"

File.open("testfile") {|f| f.path} # => "testfile"
Псевдоним для: path
tty?()

Возвращает true если поток связан с устройством терминала (tty), false в противном случае:

f = File.new('t.txt').isatty    #=> false
f.close
f = File.new('/dev/tty').isatty #=> true
f.close

IO#tty? — псевдоним для IO#isatty.

Псевдоним для: isatty
ungetbyte(integer) → nil Показать исходный код
ungetbyte(string) → nil
VALUE
rb_io_ungetbyte(VALUE io, VALUE b)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    switch (TYPE(b)) {
      case T_NIL:
        return Qnil;
      case T_FIXNUM:
      case T_BIGNUM: ;
        VALUE v = rb_int_modulo(b, INT2FIX(256));
        unsigned char c = NUM2INT(v) & 0xFF;
        b = rb_str_new((const char *)&c, 1);
        break;
      default:
        SafeStringValue(b);
    }
    io_ungetbyte(b, fptr);
    return Qnil;
}

Возвращает nil. См. Байтовый ввод/вывод.

Обратите внимание, что:

  • Вызов метода не оказывает никакого влияния при чтении без буферизации (например, IO#sysread).

  • Вызов rewind в потоке отбрасывает отложенные данные.

Когда аргумент integer задан, используется только его младший байт:

File.write('t.tmp', '012')
f = File.open('t.tmp')
f.ungetbyte(0x41)   # => nil
f.read              # => "A012"
f.rewind
f.ungetbyte(0x4243) # => nil
f.read              # => "C012"
f.close

Когда аргумент string задан, используются все байты:

File.write('t.tmp', '012')
f = File.open('t.tmp')
f.ungetbyte('A')    # => nil
f.read              # => "A012"
f.rewind
f.ungetbyte('BCDE') # => nil
f.read              # => "BCDE012"
f.close
ungetc(integer) → nil Показать исходный код
ungetc(string) → nil
VALUE
rb_io_ungetc(VALUE io, VALUE c)
{
    rb_io_t *fptr;
    long len;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    if (FIXNUM_P(c)) {
        c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
    }
    else if (RB_BIGNUM_TYPE_P(c)) {
        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;
}

Возвращает заданные данные в буфер потока («размещает» назад), размещая данные так, чтобы они были следующими для чтения; возвращает nil. См. Ввод-вывод символов.

Обратите внимание, что:

  • Вызов метода не имеет эффекта при чтении без буферизации (например, IO#sysread).

  • Вызов rewind в потоке приводит к отбрасыванию помещенных данных.

Когда в качестве аргумента используется integer, интерпретирует целое число как символ:

File.write('t.tmp', '012')
f = File.open('t.tmp')
f.ungetc(0x41)     # => nil
f.read             # => "A012"
f.rewind
f.ungetc(0x0442)   # => nil
f.getc.ord         # => 1090
f.close

Когда в качестве аргумента используется string, использует все символы:

File.write('t.tmp', '012')
f = File.open('t.tmp')
f.ungetc('A')      # => nil
f.read      # => "A012"
f.rewind
f.ungetc("\u0442\u0435\u0441\u0442") # => nil
f.getc.ord      # => 1090
f.getc.ord      # => 1077
f.getc.ord      # => 1089
f.getc.ord      # => 1090
f.close
wait(events, timeout) → event mask, false or nil Показать исходный код
wait(timeout = nil, mode = :read) → self, true, or false
static VALUE
io_wait(int argc, VALUE *argv, VALUE io)
{
#ifndef HAVE_RB_IO_WAIT
    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;
#else
    VALUE timeout = Qundef;
    rb_io_event_t events = 0;
    int i, return_io = 0;

    /* The documented signature for this method is actually incorrect.
     * A single timeout is allowed in any position, and multiple symbols can be given.
     * Whether this is intentional or not, I don't know, and as such I consider this to
     * be a legacy/slow path. */
    if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
        /* We'd prefer to return the actual mask, but this form would return the io itself: */
        return_io = 1;

        /* Slow/messy path: */
        for (i = 0; i < argc; i += 1) {
            if (RB_SYMBOL_P(argv[i])) {
                events |= wait_mode_sym(argv[i]);
            }
            else if (timeout == Qundef) {
                rb_time_interval(timeout = argv[i]);
            }
            else {
                rb_raise(rb_eArgError, "timeout given more than once");
            }
        }

        if (timeout == Qundef) timeout = Qnil;

        if (events == 0) {
            events = RUBY_IO_READABLE;
        }
    }
    else /* argc == 2 and neither are symbols */ {
        /* This is the fast path: */
        events = io_event_from_value(argv[0]);
        timeout = argv[1];
    }

    if (events & RUBY_IO_READABLE) {
        rb_io_t *fptr = NULL;
        RB_IO_POINTER(io, fptr);

        if (rb_io_read_pending(fptr)) {
            /* This was the original behaviour: */
            if (return_io) return Qtrue;
            /* New behaviour always returns an event mask: */
            else return RB_INT2NUM(RUBY_IO_READABLE);
        }
    }

    return io_wait_event(io, events, timeout, return_io);
#endif
}

Ожидает, пока IO станет готов к указанным событиям, и возвращает подмножество событий, которые стали готовыми, или ложное значение при истечении времени ожидания.

События могут быть битовой маской из IO::READABLE, IO::WRITABLE или IO::PRIORITY.

Возвращает истинное значение немедленно, когда доступны данные в буфере.

Необязательный параметр mode — одно из :read, :write, или :read_write.

Для использования этого метода необходимо подключить модуль 'io/wait'.

Также алиасируется как: wait
wait_priority → truthy or falsy Показать исходный код
wait_priority(timeout) → truthy or falsy
static VALUE
io_wait_priority(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr = NULL;

    RB_IO_POINTER(io, fptr);
    rb_io_check_readable(fptr);

    if (rb_io_read_pending(fptr)) return Qtrue;

    rb_check_arity(argc, 0, 1);
    VALUE timeout = argc == 1 ? argv[0] : Qnil;

    return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
}

Ожидает, пока IO станет приоритетным и возвращает истинное значение или ложное значение при истечении времени ожидания. Приоритетные данные отправляются и принимаются с флагом Socket::MSG_OOB и, как правило, ограничены потоками.

Для использования этого метода необходимо подключить модуль 'io/wait'.

Также алиасируется как: wait_priority
wait_readable → truthy or falsy Показать исходный код
wait_readable(timeout) → truthy or falsy
static VALUE
io_wait_readable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
#ifndef HAVE_RB_IO_WAIT
    struct timeval timerec;
    struct timeval *tv;
#endif

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);

#ifndef HAVE_RB_IO_WAIT
    tv = get_timeout(argc, argv, &timerec);
#endif
    if (rb_io_read_pending(fptr)) return Qtrue;

#ifndef HAVE_RB_IO_WAIT
    if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
        return io;
    }
    return Qnil;
#else
    rb_check_arity(argc, 0, 1);
    VALUE timeout = (argc == 1 ? argv[0] : Qnil);

    return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
#endif
}

Ожидает, пока IO станет доступным для чтения и возвращает истинное значение, или ложное значение при истечении времени ожидания. Возвращает истинное значение немедленно, когда доступны данные в буфере.

Для использования этого метода необходимо подключить модуль 'io/wait'.

Также алиасируется как: wait_readable
wait_writable → truthy or falsy Показать исходный код
wait_writable(timeout) → truthy or falsy
static VALUE
io_wait_writable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
#ifndef HAVE_RB_IO_WAIT
    struct timeval timerec;
    struct timeval *tv;
#endif

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

#ifndef HAVE_RB_IO_WAIT
    tv = get_timeout(argc, argv, &timerec);
    if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
        return io;
    }
    return Qnil;
#else
    rb_check_arity(argc, 0, 1);
    VALUE timeout = (argc == 1 ? argv[0] : Qnil);

    return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
#endif
}

Ожидает, пока IO станет доступным для записи и возвращает истинное значение или ложное значение при истечении времени ожидания.

Для использования этого метода необходимо подключить модуль 'io/wait'.

Также алиасируется как: wait_writable
winsize → [rows, columns] Показать исходный код
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)) sys_fail_fptr(fptr);
    return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}

Возвращает размер консоли.

Для использования этого метода необходимо подключить модуль 'io/console'.

winsize = [rows, columns] Показать исходный код
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;
    BOOL ret;
#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)) sys_fail_fptr(fptr);
#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");
    }
    ws.dwSize.X = newcol;
    ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
    ws.srWindow.Left = 0;
    ws.srWindow.Top = 0;
    ws.srWindow.Right = newcol-1;
    ws.srWindow.Bottom = newrow-1;
    if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
    }
    /* retry when shrinking buffer after shrunk window */
    if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
    }
    /* remove scrollbar if possible */
    if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
    }
#endif
    return io;
}

Пытается установить размер консоли. Эффект зависит от платформы и среды выполнения.

Для использования этого метода необходимо подключить модуль 'io/console'.

write(*objects) → integer Показать исходный код
static VALUE
io_write_m(int argc, VALUE *argv, VALUE io)
{
    if (argc != 1) {
        return io_writev(argc, argv, io);
    }
    else {
        VALUE str = argv[0];
        return io_write(io, str, 0);
    }
}

Записывает каждый из переданных objects в self, который должен быть открыт для записи (см. Режимы доступа); возвращает общее количество записанных байтов; каждый из objects , который не является строкой, преобразуется с помощью метода to_s.

$stdout.write('Hello', ', ', 'World!', "\n") # => 14
$stdout.write('foo', :bar, 2, "\n")          # => 8

Вывод:

Hello, World!
foobar2

Связанно с: IO#read.

write_nonblock(string) → integer Показать исходный код
write_nonblock(string [, options]) → integer
# File io.rb, line 120
def write_nonblock(buf, exception: true)
  Primitive.io_write_nonblock(buf, exception)
end

Записывает заданную строку в ios, используя системный вызов write(2) после установки O_NONBLOCK для базового дескриптора файла.

Возвращает количество записанных байтов.

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, write_nonblock не поддерживается в зависимости от типа объекта IO. В таких случаях write_nonblock вызывает Errno::EBADF.

Указав ключевой аргумент exception в false, вы можете указать, что write_nonblock не должна вызывать исключение IO::WaitWritable, а вместо этого возвращать символ :wait_writable.

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API