Spec-Zone.ru › Ruby 3.4

класс 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, подключенный к заданному источнику: потоку, файлу или дочернему процессу.

Как и поток File, поток 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: Флаги открытия файла Integer; Если 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 имеет целочисленную позицию, неотрицательную, которая является байтовым смещением, в котором должно произойти следующее чтение или запись. Новый поток имеет позицию ноль (и номер строки ноль); метод rewind сбрасывает позицию (и номер строки) до нуля.

Эти методы отбрасывают буферы и экземпляры Encoding::Converter, используемые для этого IO.

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

  • 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 поддерживает ориентированный на строки ввод для файлов и потоков IO.

Ввод по строкам из файла

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

  • IO.foreach: Читает каждую строку и передает ее заданному блоку.

  • IO.readlines: Читает и возвращает все строки в массиве.

Для каждого из этих методов:

  • Вы можете указать параметры открытия.

  • Разбор строк зависит от эффективного разделителя строк; см. Разделитель строк.

  • Длина каждой возвращаемой строки зависит от эффективного ограничения строки; см. Ограничение строки.

Ввод по строкам из потока

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

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

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

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

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

Для каждого из этих методов:

  • Чтение может начинаться посреди строки, в зависимости от позиции потока; см. Позиция.

  • Разбор строк зависит от эффективного разделителя строк; см. Разделитель строк.

  • Длина каждой возвращаемой строки зависит от эффективного ограничения строки; см. Ограничение строки.

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

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

Стандартный разделитель строк взят из глобальной переменной $/, начальное значение которой "\n".

Как правило, следующая строка для чтения — это все данные от текущей позиции до следующего разделителя строк (но см. Специальные значения разделителей строк):

f = File.new('t.txt')
# Method gets with no sep argument returns the next line, according to $/.
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

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

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

Или установив глобальную переменную $/:

f = File.new('t.txt')
$/ = 'l'
f.gets # => "First l"
f.gets # => "ine\nSecond l"
f.gets # => "ine\n\nFourth l"
f.close
Специальные значения разделителей строк

Каждый из методов ввода по строкам принимает два специальных значения для параметра sep:

  • 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
    
Предел строки

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

Значение предела по умолчанию — -1; любое отрицательное значение предела означает, что предела нет.

Если предела нет, строка определяется только 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.

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

Пример:

File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
File.open('t.txt') {|f| f.gets('li', 2) }  # => "Fi"
Номер строки

Читаемый поток IO имеет целое число номер строки, неотрицательное:

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

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

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

  • 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"

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

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 построчно с помощью этого метода:

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

Работа с символами IO

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

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

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

  • IO#ungetc: Возвращает («сдвигает») символ или целое число обратно в поток.

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

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

Работа с байтами IO

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

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

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

  • IO#ungetbyte: Возвращает («сдвигает») байт обратно в поток.

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

Работа с кодовыми точками IO

Вы можете обрабатывать поток IO кодовая точка за кодовой точкой:

  • 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 байтов, прочитанных из себя с помощью низкоуровневого чтения.

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

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

Другое

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

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

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

Константы

EWOULDBLOCKWaitReadable

то же, что и IO::EAGAINWaitReadable

EWOULDBLOCKWaitWritable

то же, что и IO::EAGAINWaitWritable

PRIORITY

Маска событий приоритета для IO#wait.

READABLE

Маска событий для чтения для IO#wait.

SEEK_CUR

Позиция ввода-вывода относительно текущей позиции

SEEK_DATA

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

SEEK_END

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

SEEK_HOLE

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

SEEK_SET

Позиция ввода-вывода от начала

WRITABLE

Маска событий записи для IO#wait.

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

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
    };
    struct rb_io_encoding 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(path, строка, 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;
    VALUE sym = 0;

    rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);

    if (argc) {
        Check_Type(sym = argv[0], T_SYMBOL);
    }

    // Force the class to be File.
    if (klass == rb_cIO) klass = rb_cFile;

    if (console_dev_get(klass, &con)) {
        if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
            console_dev_remove(klass);
            con = 0;
        }
    }

    if (sym) {
        if (sym == ID2SYM(id_close) && argc == 1) {
            if (con) {
                rb_io_close(con);
                console_dev_remove(klass);
                con = 0;
            }
            return Qnil;
        }
    }

    if (!con) {
#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;
#endif
        int fd;
        VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));

#ifdef CONSOLE_DEVICE_FOR_WRITING
        fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
        if (fd < 0) return Qnil;
        out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
#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;
        }

        con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
#ifdef CONSOLE_DEVICE_FOR_WRITING
        rb_io_set_write_io(con, out);
#endif
        console_dev_set(klass, con);
    }

    if (sym) {
        return rb_f_send(argc, argv, con);
    }

    return con;
}

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

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

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

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"
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
foreach(path, limit, **opts) {|line| block } → nil
foreach(path, sep, limit, **opts) {|line| block } → nil
foreach(...) → перечислитель
Исходный код
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), этот метод потенциально уязвим к атакам с использованием ненадёжных входных данных; см. Внедрение команд.

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

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

File.foreach('t.txt') {|line| p line }

Вывод: такой же, как выше.

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

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

File.foreach('t.txt', 'li') {|line| p line }

Вывод:

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

Каждый абзац:

File.foreach('t.txt', '') {|paragraph| p paragraph }

Вывод:

"First line\nSecond line\n\n"
"Third line\nFourth line\n"

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

File.foreach('t.txt', 7) {|line| p line }

Вывод:

"First l"
"ine\n"
"Second "
"line\n"
"\n"
"Third l"
"ine\n"
"Fourth l"
"line\n"

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

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

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

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

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

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

new(fd, mode = 'r', **opts) → io
Исходный код
static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
    VALUE fnum, vmode;
    VALUE opt;

    rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
    return io_initialize(io, fnum, vmode, opt);
}

Создаёт и возвращает новый объект 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 и возвращает значение блока.

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 является строкой длиной 1 символ '-', вызывает разделение процесса:

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

Вывод:

["Linux\n"]

Ещё один пример:

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

Вывод:

213

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

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

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

Вывод:

1111

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

Когда аргумент cmd является массивом, чьим первым элементом является массив строк из 2 элементов, и оставшиеся элементы (если есть) являются строками:

  • 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(path, length = nil, offset = 0, **opts) → string or nil
Исходный код
static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
    VALUE opt, offset;
    long off;
    struct foreach_arg arg;

    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
    if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
        rb_raise(rb_eArgError, "negative offset %ld given", off);
    }
    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), этот метод имеет потенциальные уязвимости в области безопасности при вызове с недоверенным вводом; см. Инъекция команд.

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

При указании только аргумента 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 задают:

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

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

END_OF_DOCUMENT_MARKER
readlines(path, sep = $/, **opts) → array
readlines(path, limit, **opts) → array
readlines(path, sep, limit, **opts) → array
Source
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) этот метод имеет потенциальные уязвимости безопасности, если вызывается с ненадежным вводом; см. Command Injection.

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

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

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

С аргументом sep анализирует строки, определяемые этим разделителем строк (см. Line Separator):

# 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 анализирует строки, определяемые разделителем строк по умолчанию и заданным ограничением длины строки (см. Line Separator и Line Limit):

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

С аргументами sep и limit сочетает два поведения (см. Line Separator and Line Limit).

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

  • Open Options.

  • Encoding options.

  • Line Options.

select(read_ios, write_ios = [], error_ios = [], timeout = nil) → array or nil
Source
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 socket socket, когда несколько процессов читают из потока.

Наконец, разработчики ядра 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
Source
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 {
        StringValue(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
Source
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(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), этот метод может иметь потенциальные уязвимости в случае использования небезопасного ввода; см. Инъекция команд.

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

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

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
Исходный код
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
Исходный код
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
Исходный код
static VALUE
rb_io_set_autoclose(VALUE io, VALUE autoclose)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (!RTEST(autoclose))
        fptr->mode |= FMODE_EXTERNAL;
    else
        fptr->mode &= ~FMODE_EXTERNAL;
    return autoclose;
}

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

f = File.open(File::NULL)
IO.for_fd(f.fileno).close
f.gets # raises Errno::EBADF

f = File.open(File::NULL)
g = IO.for_fd(f.fileno)
g.autoclose = false
g.close
f.gets # won't cause Errno::EBADF
autoclose? → true or false
Исходный код
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_EXTERNAL));
}

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

beep
Исходный код
static VALUE
console_beep(VALUE io)
{
#ifdef _WIN32
    MessageBeep(0);
#else
    int fd = GetWriteFD(io);
    if (write(fd, "\a", 1) < 0) sys_fail(io);
#endif
    return io;
}

Издает звуковой сигнал на выходной консоли.

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

binmode → self
Исходный код
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
Исходный код
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 { ... } → io
Исходный код
static VALUE
console_check_winsize_changed(VALUE io)
{
    HANDLE h;
    DWORD num;

    h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
    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;
}

Выполняет yield, пока события ввода с консоли находятся в очереди.

Этот метод работает только в Windows.

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

clear_screen → io
Исходный код
static VALUE
console_clear_screen(VALUE io)
{
    console_erase_screen(io, INT2FIX(2));
    console_goto(io, INT2FIX(0), INT2FIX(0));
    return io;
}

Очищает весь экран и перемещает курсор в верхний левый угол.

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

close → nil
Исходный код
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, который уже закрыт, не является ошибкой. Он просто возвращает nil.

Пример:

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
Исходный код
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 = File.open(File::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
Исходный код
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
Исходный код
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
Исходный код
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
Исходный код
VALUE
rb_io_closed_p(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;
    int fd = GetReadFD(io);

    if (!getattr(fd, &t)) sys_fail(io);

    return conmode_new(cConmode, &t);
}

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

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

console_mode = mode
Исходный код
static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
    conmode *t, r;
    int fd = GetReadFD(io);

    TypedData_Get_Struct(mode, conmode, &conmode_type, t);
    r = *t;

    if (!setattr(fd, &r)) sys_fail(io);

    return mode;
}

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

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cooked {|io| }
Исходный код
static VALUE
console_cooked(VALUE io)
{
    return ttymode(io, rb_yield, io, set_cookedmode, NULL);
}

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

STDIN.cooked(&:gets)

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

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cooked!
Исходный код
static VALUE
console_set_cooked(VALUE io)
{
    conmode t;
    int fd = GetReadFD(io);
    if (!getattr(fd, &t)) sys_fail(io);
    set_cookedmode(&t, NULL);
    if (!setattr(fd, &t)) sys_fail(io);
    return io;
}

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

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

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor → [row, column]
Исходный код
static VALUE
console_cursor_pos(VALUE io)
{
#ifdef _WIN32
    rb_console_size_t ws;
    int fd = GetWriteFD(io);
    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));
#else
    static const struct query_args query = {"\033[6n", 0};
    VALUE resp = console_vt_response(0, 0, io, &query);
    VALUE row, column, term;
    unsigned int r, c;
    if (!RB_TYPE_P(resp, T_ARRAY) || RARRAY_LEN(resp) != 3) return Qnil;
    term = RARRAY_AREF(resp, 2);
    if (!RB_TYPE_P(term, T_STRING) || RSTRING_LEN(term) != 1) return Qnil;
    if (RSTRING_PTR(term)[0] != 'R') return Qnil;
    row = RARRAY_AREF(resp, 0);
    column = RARRAY_AREF(resp, 1);
    rb_ary_resize(resp, 2);
    r = NUM2UINT(row) - 1;
    c = NUM2UINT(column) - 1;
    RARRAY_ASET(resp, 0, INT2NUM(r));
    RARRAY_ASET(resp, 1, INT2NUM(c));
    return resp;
#endif
}

Возвращает текущее положение курсора в виде двумерного массива целых чисел (строка, столбец)

io.cursor # => [3, 5]

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor = [line, column] → io
Исходный код
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));
}

То же, что и io.goto(line, column)

См. IO#goto.

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor_down(n) → io
Исходный код
static VALUE
console_cursor_down(VALUE io, VALUE val)
{
    return console_move(io, +NUM2INT(val), 0);
}

Перемещает курсор вниз на n строк.

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor_left(n) → io
Исходный код
static VALUE
console_cursor_left(VALUE io, VALUE val)
{
    return console_move(io, 0, -NUM2INT(val));
}

Перемещает курсор влево на n столбцов.

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor_right(n) → io
Исходный код
static VALUE
console_cursor_right(VALUE io, VALUE val)
{
    return console_move(io, 0, +NUM2INT(val));
}

Перемещает курсор вправо на n столбцов.

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

cursor_up(n) → io
Исходный код
static VALUE
console_cursor_up(VALUE io, VALUE val)
{
    return console_move(io, -NUM2INT(val), 0);
}

Перемещает курсор вверх на n строк.

Необходимо подключить ‘io/console’, чтобы использовать этот метод.

each
Исходный код
Также известен как: each_line
each_byte {|byte| ... } → self
each_byte → enumerator
Исходный код
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. См. Байтовый ввод/вывод.

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 → enumerator
Исходный код
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. См. Символьный ввод/вывод.

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 → enumerator
Исходный код
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 → enumerator

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

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

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, объединяет оба поведения (см. Разделитель и предел строки).

Необязательный ключевой аргумент 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, если блок не задан.

Псевдоним для: each
echo = flag
Исходный код
static VALUE
console_set_echo(VALUE io, VALUE f)
{
    conmode t;
    int fd = GetReadFD(io);

    if (!getattr(fd, &t)) sys_fail(io);

    if (RTEST(f))
        set_echo(&t, NULL);
    else
        set_noecho(&t, NULL);

    if (!setattr(fd, &t)) sys_fail(io);

    return io;
}

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

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

echo? → true or false
Исходный код
static VALUE
console_echo_p(VALUE io)
{
    conmode t;
    int fd = GetReadFD(io);

    if (!getattr(fd, &t)) sys_fail(io);
    return echo_p(&t) ? Qtrue : Qfalse;
}

Возвращает true если отображение ввода включено.

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

eof → true or 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 является потоком, таким как pipe или сокет, этот метод блокируется до тех пор, пока другой конец не отправит данные или не закроет его:

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 сначала (что недоступно для некоторых потоков).

Также алиас: eof?
eof?
Псевдоним для: eof
erase_line(mode) → io
Исходный код
static VALUE
console_erase_line(VALUE io, VALUE val)
{
    int mode = mode_in_range(val, 2, "line erase");
#ifdef _WIN32
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;

    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
    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;
#else
    rb_io_write(io, rb_sprintf(CSI "%dK", mode));
#endif
    return io;
}

Очищает строку в курсоре, соответствующую mode. mode может быть: 0: после курсора 1: перед и в курсоре 2: вся строка

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

erase_screen(mode) → io
Исходный код
static VALUE
console_erase_screen(VALUE io, VALUE val)
{
    int mode = mode_in_range(val, 3, "screen erase");
#ifdef _WIN32
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;

    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
    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);
#else
    rb_io_write(io, rb_sprintf(CSI "%dJ", mode));
#endif
    return io;
}

Очищает экран в курсоре, соответствующем mode. mode может быть: 0: после курсора 1: перед и в курсоре 2: весь экран

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

IO#expect(pattern,timeout=9999999) → Array
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 → 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(integer_cmd, argument) → integer
Исходный код
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), который предоставляет механизм для выдачи команд низкого уровня для управления или запроса потока ввода-вывода ориентированного на файлы. Аргументы и результаты зависят от платформы.

Если argument является числом, его значение передаётся непосредственно; если это строка, она интерпретируется как двоичная последовательность байтов. (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_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
        return INT2FIX(0);

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

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

fileno → integer
Исходный код
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
Также алиас: 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_io_blocking_region(fptr, nogvl_fsync, fptr))
        rb_sys_fail_path(fptr->pathv);

    return INT2FIX(0);
}

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

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

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

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

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

getbyte → integer или 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);
}

Считывает и возвращает следующую строку из одного символа из потока; возвращает 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) → char
Исходный код
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) → string
Исходный код
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);
    rb_io_flush(wio);
    str = rb_ensure(getpass_call, io, puts_call, wio);
    return str_chomp(str);
}

Считывает и возвращает строку без отображения ввода. Выводит prompt за исключением случаев, когда он nil.

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

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

require 'io/console'
IO::console.getpass("Enter password:")
Enter password:
# => "mypassword"
gets(sep = $/, chomp: false) → string или nil
gets(limit, chomp: false) → string или nil
gets(sep, limit, chomp: false) → string или 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 объединяет оба поведения (см. Разделитель строк и предел строк).

Необязательный ключевой аргумент 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(line, column) → io
Исходный код
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
#ifdef _WIN32
    COORD pos;
    int fd = GetWriteFD(io);
    pos.X = NUM2UINT(x);
    pos.Y = NUM2UINT(y);
    if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
#else
    rb_io_write(io, rb_sprintf(CSI "%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
#endif
    return io;
}

Set позицию курсора в line и column.

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

END_OF_DOCUMENT_MARKER
goto_column(column) → io
Исходный код
static VALUE
console_goto_column(VALUE io, VALUE val)
{
#ifdef _WIN32
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;

    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
    if (!GetConsoleScreenBufferInfo(h, &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    pos->X = NUM2INT(val);
    if (!SetConsoleCursorPosition(h, *pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
#else
    rb_io_write(io, rb_sprintf(CSI "%dG", NUM2UINT(val)+1));
#endif
    return io;
}

Set позицию курсора в column на той же строке, что и текущая позиция.

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

iflush
Исходный код
static VALUE
console_iflush(VALUE io)
{
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    int fd = GetReadFD(io);
    if (tcflush(fd, TCIFLUSH)) sys_fail(io);
#endif

    return io;
}

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

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

inspect → string
Исходный код
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 → encoding or 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) → integer
Исходный код
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)
{
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    int fd1 = GetReadFD(io);
    int fd2 = GetWriteFD(io);

    if (fd2 != -1 && fd1 != fd2) {
        if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
        if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
    }
    else {
        if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
    }
#endif

    return io;
}

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

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

isatty → true or 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
Также алиас: tty?
lineno → integer
Исходный код
static VALUE
rb_io_lineno(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    return INT2NUM(fptr->lineno);
}

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

lineno = integer → integer
Исходный код
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| } → object
nonblock(boolean) {|io| } → object
Исходный код
static VALUE
rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
{
    int nb = 1;

    int descriptor = rb_io_descriptor(self);

    if (argc > 0) {
        VALUE v;
        rb_scan_args(argc, argv, "01", &v);
        nb = RTEST(v);
    }

    int current_flags = get_fcntl_flags(descriptor);
    int restore[2] = {descriptor, current_flags};

    if (!io_nonblock_set(descriptor, current_flags, nb))
        return rb_yield(self);

    return rb_ensure(rb_yield, self, io_nonblock_restore, (VALUE)restore);
}

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

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

nonblock = boolean → boolean
Исходный код
static VALUE
rb_io_nonblock_set(VALUE self, VALUE value)
{
    if (RTEST(value)) {
        rb_io_t *fptr;
        GetOpenFile(self, fptr);
        rb_io_set_nonblock(fptr);
    }
    else {
        int descriptor = rb_io_descriptor(self);
        io_nonblock_set(descriptor, get_fcntl_flags(descriptor), RTEST(value));
    }

    return self;
}

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

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

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

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

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

Поскольку флаг общий для процессов и многие внешние команды не ожидают стандартного ввода-вывода в режиме без ожидания, было бы безопасно сбросить флаг перед завершением программы 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)
{
    if (get_fcntl_flags(rb_io_descriptor(io)) & 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);

#ifdef HAVE_RB_IO_DESCRIPTOR
    int fd = rb_io_descriptor(io);
#else
    int fd = fptr->fd;
#endif

    if (!FIONREAD_POSSIBLE_P(fd)) return INT2FIX(0);
    if (ioctl(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)
{
    int fd = GetWriteFD(io);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    if (tcflush(fd, TCOFLUSH)) sys_fail(io);
#endif
    (void)fd;
    return io;
}

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

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

END_OF_DOCUMENT_MARKER
path → строка или nil
Исходный код
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(name) → Целое число
Исходный код
static VALUE
io_pathconf(VALUE io, VALUE arg)
{
    int name;
    long ret;

    name = NUM2INT(arg);

    errno = 0;
    ret = fpathconf(rb_io_descriptor(io), 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 → целое число или 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
Псевдоним для: 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) → строка
pread(maxlen, offset, out_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.io = 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?(key) → bool
Исходный код
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;
}

Возвращает true если key нажата. key может быть кодом виртуальной клавиши или её именем (String или Symbol) без префикса “VK_”.

Этот метод доступен только для Windows.

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

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
puts(*objects) → nil
Исходный код
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
    VALUE line, args[2];

    /* if no argument given, print newline. */
    if (argc == 0) {
        rb_io_write(out, rb_default_rs);
        return Qnil;
    }
    for (int i = 0; i < argc; i++) {
        // Convert the argument to a string:
        if (RB_TYPE_P(argv[i], T_STRING)) {
            line = argv[i];
        }
        else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
            continue;
        }
        else {
            line = rb_obj_as_string(argv[i]);
        }

        // Write the line:
        int n = 0;
        if (RSTRING_LEN(line) == 0) {
            args[n++] = rb_default_rs;
        }
        else {
            args[n++] = line;
            if (!rb_str_end_with_asciichar(line, '\n')) {
                args[n++] = rb_default_rs;
            }
        }

        rb_io_writev(out, n, args);
    }

    return Qnil;
}

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

Обратите внимание, что каждый добавленный перевод строки — символ "\n"<//tt>, not the output record separator (<tt>$\.

Обработка каждого объекта:

  • Строка: записывает строку.

  • Не строка и не массив: записывает object.to_s.

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

Для краткости примеров определим вспомогательный метод:

def show(*objects)
  # Puts objects to file.
  f = File.new('t.tmp', 'w+')
  f.puts(objects)
  # Return file content.
  f.rewind
  p f.read
  f.close
end

# Strings without newlines.
show('foo', 'bar', 'baz')     # => "foo\nbar\nbaz\n"
# Strings, some with newlines.
show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"

# Neither strings nor arrays:
show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
# => "0\n0.0\n0/1\n9+0i\nzero\n"

# Array of strings.
show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
# Nested arrays.
show([[[0, 1], 2, 3], 4, 5])  # => "0\n1\n2\n3\n4\n5\n"
pwrite(object, offset) → целое число
Исходный код
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.io = 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_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
    if (n < 0) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return SSIZET2NUM(n);
}

Поведение аналогично IO#write, за исключением:

  • Запись по заданному offset (в байтах).

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

  • Пропуск любого буферирования в пользовательском пространстве в потоке.

Поскольку этот метод не изменяет состояние потока (в частности, его позицию), 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| }
Исходный код
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);
}

Возвращает результат блока в режиме raw, вызывая его с self.

STDIN.raw(&:gets)

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

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

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

Если параметр intr равен true, разрешаются специальные символы для прерывания, отмены, выхода и приостановки.

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

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

raw!(min: nil, time: nil, intr: nil) → io
Исходный код
static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
    conmode t;
    rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
    int fd = GetReadFD(io);
    if (!getattr(fd, &t)) sys_fail(io);
    set_rawmode(&t, optp);
    if (!setattr(fd, &t)) sys_fail(io);
    return io;
}

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

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

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

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

read(maxlen = nil, out_string = nil) → new_string, out_string, or nil
Исходный код
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;
}

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

  • Если 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
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 при EOF.

На некоторых платформах, таких как 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. При EOF он вернет nil вместо возбуждения EOFError.

readbyte → integer
Исходный код
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, если достигнут конец потока. См. Байтовый ввод-вывод.

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
Исходный код
static VALUE
rb_io_readchar(VALUE io)
{
    VALUE c = rb_io_getc(io);

    if (NIL_P(c)) {
        rb_eof_error();
    }
    return c;
}

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

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
Исходный код
# File io.rb, line 133
def readline(sep = $/, limit = nil, chomp: false)
  Primitive.io_readline(sep, limit, chomp)
end

Читает строку, как с IO#gets, но возбуждает EOFError, если достигнут конец потока.

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

readlines(sep = $/, chomp: false) → массив
readlines(limit, chomp: false) → массив
readlines(sep, limit, chomp: false) → массив
Исходный код
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 объединяет оба поведения (см. Разделитель строк и ограничение длины строки).

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

f = File.new('t.txt')
f.readlines(chomp: true)
# => ["First line", "Second line", "", "Fourth line", "Fifth line"]
f.close
readpartial(maxlen) → строка
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. При встрече 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? → истинно или ложно
Исходный код
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;
        struct rb_io_encoding convconfig;

        rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
        if (RUBY_IO_EXTERNAL_P(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(n) → io
Исходный код
static VALUE
console_scroll_backward(VALUE io, VALUE val)
{
    return console_scroll(io, -NUM2INT(val));
}

Прокручивает весь поток на n строк назад.

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

scroll_forward(n) → io
Исходный код
static VALUE
console_scroll_forward(VALUE io, VALUE val)
{
    return console_scroll(io, +NUM2INT(val));
}

Прокручивает весь поток на n строк вперед.

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

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

См. Encodings.

Аргумент ext_enc, если задан, должен быть объектом Encoding или String с именем кодировки; он назначается в качестве кодировки для потока.

Аргумент int_enc, если задан, должен быть объектом Encoding или String с именем кодировки; он назначается в качестве кодировки для внутренней строки.

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

Если внешняя кодировка строки является binary/ASCII-8BIT, внутренняя кодировка строки устанавливается в nil, поскольку транскодирование не требуется.

Необязательные именованные аргументы enc_opts указывают параметры кодировки.

set_encoding_by_bom → encoding or 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 or 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;
}

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

Значения для режима синхронизации:

  • true: Весь вывод немедленно отправляется в базовую операционную систему и не буферизуется внутренне.

  • false: Вывод может буферизоваться внутренне.

Пример;

f = File.open('t.tmp', 'w')
f.sync # => false
f.sync = true
f.sync # => true
f.close

Связанные: IO#fsync.

sysread(maxlen) → string
sysread(maxlen, out_string) → 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) → integer
Исходный код
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) → integer
Исходный код
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 в self, который должен быть открыт для записи (см. Режимы); возвращает количество записанных байтов. Если object не является строкой, он преобразуется с помощью метода to_s:

f = File.new('t.tmp', 'w')
f.syswrite('foo') # => 3
f.syswrite(30)    # => 2
f.syswrite(:foo)  # => 3
f.close

Этот метод не следует использовать с другими методами записи потока.

tell → integer
Исходный код
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.

Также является псевдонимом для: fileno
timeout → duration or nil
Исходный код
VALUE
rb_io_timeout(VALUE self)
{
    rb_io_t *fptr = rb_io_get_fptr(self);

    return fptr->timeout;
}

Получить внутреннюю длительность тайм-аута или nil, если он не был установлен.

timeout = duration → duration
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;
}

Устанавливает внутренний тайм-аут на указанную длительность или nil. Тайм-аут применяется ко всем блокирующим операциям, где это возможно.

Когда операция выполняется дольше, чем установленный тайм-аут, возникает IO::TimeoutError.

Это влияет на следующие методы (но не ограничивается ими): gets, puts, read, write, wait_readable и wait_writable. Это также влияет на блокирующие операции сокета, такие как Socket#accept и Socket#connect.

На некоторые операции, такие как File#open и IO#close, тайм-аут не влияет. Тайм-аут во время операции записи может привести к тому, что IO окажется в несогласованном состоянии, например, данные были частично записаны. В общем, тайм-аут — это последняя попытка предотвратить зависание приложения на медленных операциях ввода-вывода, таких как те, которые происходят во время атаки slowloris.

to_i
Псевдоним для: fileno
to_io → self
Исходный код
static VALUE
rb_io_to_io(VALUE io)
{
    return io;
}

Возвращает self.

to_path
Псевдоним для: path
tty?
Псевдоним для: isatty
ttyname → string or nil
Исходный код
static VALUE
console_ttyname(VALUE io)
{
    int fd = rb_io_descriptor(io);
    if (!isatty(fd)) return Qnil;
# if defined _WIN32
    return rb_usascii_str_new_lit("con");
# elif defined HAVE_TTYNAME_R
    {
        char termname[1024], *tn = termname;
        size_t size = sizeof(termname);
        int e;
        if (ttyname_r(fd, tn, size) == 0)
            return rb_interned_str_cstr(tn);
        if ((e = errno) == ERANGE) {
            VALUE s = rb_str_new(0, size);
            while (1) {
                tn = RSTRING_PTR(s);
                size = rb_str_capacity(s);
                if (ttyname_r(fd, tn, size) == 0) {
                    return rb_str_to_interned_str(rb_str_resize(s, strlen(tn)));
                }
                if ((e = errno) != ERANGE) break;
                if ((size *= 2) >= INT_MAX/2) break;
                rb_str_resize(s, size);
            }
        }
        rb_syserr_fail_str(e, rb_sprintf("ttyname_r(%d)", fd));
        UNREACHABLE_RETURN(Qnil);
    }
# elif defined HAVE_TTYNAME
    {
        const char *tn = ttyname(fd);
        if (!tn) {
            int e = errno;
            rb_syserr_fail_str(e, rb_sprintf("ttyname(%d)", fd));
        }
        return rb_interned_str_cstr(tn);
    }
# else
#   error No ttyname function
# endif
}

Возвращает имя связанного терминала (tty), если io не является tty. Возвращает nil в противном случае.

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:
        StringValue(b);
    }
    io_ungetbyte(b, fptr);
    return Qnil;
}

Возвращает данные в буфер потока, размещая данные так, чтобы их можно было прочитать следующими; возвращает nil. См. Byte IO.

Обратите внимание, что:

  • Вызов метода не оказывает никакого эффекта при небуферизованном чтении (например, 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 {
        StringValue(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. См. Character IO.

Обратите внимание, что:

  • Вызов метода не оказывает никакого эффекта при небуферизованном чтении (например, 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.

Для использования этого метода необходимо require ‘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 и обычно ограничены потоками.

Для использования этого метода необходимо require ‘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 не станет доступен для чтения, и возвращает истинное значение или ложное значение при истечении времени ожидания. Возвращает истинное значение немедленно, когда доступны буферизованные данные.

Для использования этого метода необходимо require ‘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 не станет доступен для записи, и возвращает истинное значение или ложное значение при истечении времени ожидания.

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

Также имеет псевдоним: wait_writable
winsize → [rows, columns]
Исходный код
static VALUE
console_winsize(VALUE io)
{
    rb_console_size_t ws;
    int fd = GetWriteFD(io);
    if (!getwinsize(fd, &ws)) sys_fail(io);
    return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}

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

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

winsize = [rows, columns]
Исходный код
static VALUE
console_set_winsize(VALUE io, VALUE size)
{
    rb_console_size_t ws;
#if defined _WIN32
    HANDLE wh;
    int newrow, newcol;
    BOOL ret;
#endif
    VALUE row, col, xpixel, ypixel;
    const VALUE *sz;
    long sizelen;
    int fd;

    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(io);
#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(io);
#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;
}

Пытается установить размер консоли. Эффект зависит от платформы и среды выполнения.

Для использования этого метода необходимо require ‘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, который должен быть открыт для записи (см. Access Modes); возвращает общее количество записанных байтов; каждый из objects, который не является строкой, преобразуется с помощью метода to_s:

$stdout.write('Hello', ', ', 'World!', "\n") # => 14
$stdout.write('foo', :bar, 2, "\n")          # => 8

Вывод:

Hello, World!
foobar2

Связанное: IO#read.

write_nonblock(строка) → целое число
write_nonblock(строка [, параметры]) → целое число
Исходный код
# 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.

Указав ключевое слово исключение в false, вы можете указать, что write_nonblock не должен вызывать исключение IO::WaitWritable, а вместо этого вернуть символ :wait_writable.

Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API