Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Ruby.docx
Скачиваний:
18
Добавлен:
06.09.2019
Размер:
1.74 Mб
Скачать

10.1.4. Прямой доступ к файлу

Для чтения из файла в произвольном порядке, а не последовательно, можно воспользоваться методом seek, который класс File наследует от IO. Проще всего перейти на байт в указанной позиции. Номер позиции отсчитывается от начала файла, причем самый первый байт находится в позиции 0.

# myfile содержит строку: abcdefghi

file = File.new("myfile")

file.seek(5)

str = file.gets # "fghi"

Если все строки в файле имеют одинаковую длину, то можно перейти сразу в начало нужной строки:

# Предполагается, что все строки имеют длину 20.

# Строка N начинается с байта (N-1)*20

file = File.new("fixedlines")

file.seek(5*20) # Шестая строка!

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

file = File.new("somefile")

file.seek(55)                # Позиция 55.

file.seek(-22, IO::SEEK_CUR) # Позиция 33.

file.seek(47, IO::SEEK_CUR)  # Позиция 80.

Можно также искать относительно конца файла, в таком случае смещение может быть только отрицательным:

file.seek(-20, IO::SEEK_END) # Двадцать байтов от конца файла.

Есть еще и третья константа IO::SEEK_SET, но это значение по умолчанию (поиск относительно начала файла).

Метод tell возвращает текущее значение позиции в файле, у него есть синоним pos:

file.seek(20)

pos1 = file.tell # 20

file.seek(50, IO::SEEK_CUR)

pos2 = file.pos  # 70

Метод rewind устанавливает указатель файла в начало. Его название («обратная перемотка») восходит ко временам использования магнитных лент.

Для выполнения прямого доступа файл часто открывается в режиме обновления (для чтения и записи). Этот режим обозначается знаком + в начале строки указания режима (см. раздел 10.1.2).

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.