Чтение онлайн

ЖАНРЫ

Программирование на языке Ruby
Шрифт:

#Обратите внимание на восьмеричное 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
.

10.1.6. Блокировка файлов

В тех операционных системах, которые поддерживают такую возможность, метод

flock
класса
File
блокирует или разблокирует файл. Вторым параметром может быть одна из констант
File::LOCK_EX
,
File::LOCK_NB
,
File::LOCK_SH
,
File::LOCK_UN
или их объединение с помощью оператора ИЛИ. Понятно, что многие комбинации не имеют смысла; чаще всего употребляется флаг, задающий неблокирующий режим.

file = File.new("somefile")

file.flock(File::LOCK_EX) # Исключительная блокировка; никакой другой

# процесс не может обратиться к файлу.

file.flock(File::LOCK_UN) # Разблокировать.

file.flock(File::LOCK_SH) # Разделяемая блокировка (другие

# процессы могут сделать то же самое).

file.flock(File::LOCK_UN) # Разблокировать.

locked = file.flock(File::LOCK_EX | File::LOCK_NB)

#
Пытаемся заблокировать файл, но не приостанавливаем программу, если

# не получилось; в таком случае переменная locked будет равна false.

Для семейства операционных систем Windows эта функция не реализована.

10.1.7. Простой ввод/вывод

Вы уже знакомы с некоторыми методами ввода/вывода из модуля

Kernel
; мы вызывали их без указания вызывающего объекта. К ним относятся функции
gets
и
puts
, а также
print
,
printf
и
p
(последний вызывает метод объекта
inspect
, чтобы распечатать его в понятном для нас виде).

Но есть и другие методы, которые следует упомянуть для полноты. Метод

putc
выводит один символ. (Парный метод
getc
не реализован в модуле
Kernel
по техническим причинам, однако он есть у любого объекта класса
IO
). Если параметром является объект
String
, то печатается первый символ строки.

putc(?\n) # Вывести символ новой строки.

putc("X") # Вывести букву X.

Интересный вопрос: куда направляется вывод, если эти методы вызываются без указания объекта? Начнем с того, что в среде исполнения Ruby определены три глобальные константы, соответствующие трем стандартным потокам ввода/вывода, к которым мы привыкли в UNIX. Это

STDIN
,
STDOUT
и
STDERR
. Все они имеют тип
IO
.

Имеется также глобальная переменная

$stdout
, именно в нее направляется весь вывод, формируемый методами из
Kernel
. Она инициализирована значением
STDOUT
, так что данные отправляются на стандартный вывод, как и следовало ожидать. В любой момент переменной
$stdout
можно присвоить другое значение, являющееся объектом
IO
.

diskfile = File.new("foofile","w")

puts "Привет..." # Выводится на stdout.

$stdout = diskfile

puts "Пока!" # Выводится в файл "foofile".

diskfile.close

$stdout = STDOUT # Восстановление исходного значения.

puts "Это все." # Выводится на stdout.

Помимо метода

gets
в модуле
Kernel
есть методы ввода
readline
и
readlines
. Первый аналогичен
gets
в том смысле, что возбуждает исключение
EOFError
при попытке читать за концом файла, а не просто возвращает
nil
. Последний эквивалентен методу
IO.readlines
(то есть считывает весь файл в память).

Откуда мы получаем ввод? Есть переменная

$stdin
, которая по умолчанию равна
STDIN
. Точно так же существует поток стандартного вывода для ошибок (
$stderr
, по умолчанию равен
STDERR
).

Еще имеется интересный глобальный объект

ARGF
, представляющий конкатенацию всех файлов, указанных в командной строке. Это не объект класса
File
, хотя и напоминает таковой. По умолчанию ввод связан именно с этим объектом, если в командной строке задан хотя бы один файл.

Поделиться с друзьями: