logo
Программирование на языке Ruby

10.1.5. Работа с двоичными файлами

Когда-то давно программисты на языке С включали в строку указания режима символ "b" для открытия файла как двоичного. (Вопреки распространенному заблуждению, это относилось и к ранним версиям UNIX.) Как правило, эту возможность все еще поддерживают ради совместимости, но сегодня с двоичными файлами работать не так сложно, как раньше. Строка в Ruby может содержать двоичные данные, а для чтения двоичного файла не нужно никаких специальных действий.

Исключение составляет семейство операционных систем Windows, в которых различие все еще имеет место. Основное отличие двоичных файлов от текстовых на этой платформе состоит в том, что в двоичном режиме конец строки не преобразуется в один символ перевода строки, а представляется в виде пары «возврат каретки — перевод строки». Еще одно важное отличие — интерпретация символа control-Z как конца файла в текстовом режиме:

# Создать файл (в двоичном режиме).

File.open("myfile","wb") {|f| f.syswrite("12345\0326789\r") }

#Обратите внимание на восьмеричное 032 (^Z).

# Читать как двоичный файл.

str = nil

File.open("myfile","rb") {|f| str = f.sysread(15) )

puts str.size # 11

# Читать как текстовый файл.

str = nil

File.open("myfile","r") {|f| str = f.sysread(15) }

puts str.size # 5

В следующем фрагменте показано, что на платформе Windows символ возврата каретки не преобразуется в двоичном режиме:

# Входной файл содержит всего одну строку: Строка 1.

file = File.open("data")

line = file.readline          # "Строка 1.\n"

puts "#{line.size} символов." # 10 символов,

file.close

file = File.open("data","rb")

line = file.readline          # "Строка 1.\r\n"

puts "#{line.size} символов." # 11 символов.

file.close

Отметим, что упомянутый в коде метод binmode переключает поток в двоичный режим. После переключения вернуться в текстовый режим невозможно.

file = File.open("data")

file.binmode

line = file.readline        # "Строка 1.\r\n"

puts {line.size} символов." # 11 символов.

file.close

При необходимости выполнить низкоуровневый ввод/вывод можете воспользоваться методами sysread и syswrite. Первый принимает в качестве параметра число подлежащих чтению байтов, второй принимает строку и возвращает число записанных байтов. (Если вы начали читать из потока методом sysread, то никакие другие методы использовать не следует. Результаты могут быть непредсказуемы.)

input = File.new("infile")

output = File.new("outfile")

instr = input.sysread(10);

bytes = output.syswrite("Это тест.")

Отметим, что метод sysread возбуждает исключение EOFError при попытке вызвать его, когда достигнут конец файла (но не в том случае, когда конец файла встретился в ходе успешной операции чтения). Оба метода возбуждают исключение SystemCallError при возникновении ошибки ввода/вывода.

При работе с двоичными данными могут оказаться полезны метод pack из класса Array и метод unpack из класса String.