Программирование на языке 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.