Версия для UNIX прямолинейна. Мы переводим терминал в режим прямого ввода (raw mode) и обычно одновременно отключаем эхо-контроль.
def getchar
system('stty raw -echo') # Прямой ввод без эхо-контроля.
char = STDIN.getc
system('stty -raw echo') # Восстановить режим терминала.
char
end
На платформе Windows придется написать расширение на С. Пока что альтернативой является использование одной из функций в библиотеке Win32API
.
require 'Win32API'
def getchar
char = Win32API.new('crtdll', '_getch', [], 'L').Call
end
Поведение в обоих случаях идентично.
10.1.21. Чтение всего файла в память
Чтобы прочитать весь файл в массив, не нужно даже его предварительно открывать. Все сделает метод IO.readlines
: откроет файл, прочитает и закроет.
arr = IO.readlines('myfile')
lines = arr.size
puts 'myfile содержит #{lines} строк.'
longest = arr.collect {|x| x.length}.max
puts 'Самая длинная строка содержит #{longest} символов.'
Можно также воспользоваться методом IO.read
(который возвращает одну большую строку, а не массив строк).
str = IO.read('myfile')
bytes = arr.size
puts 'myfile содержит #{bytes} байтов.'
longest=str.collect {|x| x.length}.max # строки - перечисляемые объекты!
puts 'Самая длинная строка содержит #{longest} символов.'
Поскольку класс IO
является предком File
, то можно вместо этого писать File.deadlines
и File.read
.
10.1.22. Построчное чтение из файла
Чтобы читать по одной строке из файла, можно обратиться к методу класса IO.foreach
или к методу экземпляра each
. В первом случае файл не нужно явно открывать.
# Напечатать все строки, содержащие слово 'target'.
IO.foreach('somefile') do |line|
puts line if line =~ /target/
end
# Другой способ...
file = File.new('somefile')
file.each do |line|
puts line if line =~ /target/
end
Отметим, что each_line
— синоним each
.
10.1.23. Побайтное чтение из файла
Для чтения из файла по одному байту служит метод экземпляра each_byte
. Напомним, что он передает в блок символ (то есть целое число); воспользуйтесь методом chr
, если хотите преобразовать его в «настоящий» символ.
file = File.new('myfile')
e_count = 0
file.each_byte do |byte|
e_count += 1 if byte == ?e
end
10.1.24. Работа со строкой как с файлом
Иногда возникает необходимость рассматривать строку как файл. Что под этим понимается, зависит от конкретной задачи.
Объект определяется прежде всего своими методами. В следующем фрагменте показано, как к объекту source
применяется итератор; на каждой итерации выводится одна строка. Можете ли вы что-нибудь сказать о типе объекта source
, глядя на этот код?
source.each do |line|
puts line
end
Это могли бы быть как файл, так и строка, содержащая внутри символы новой строки. В таких случаях строку можно трактовать как файл без всякого труда.
В последних версиях Ruby имеется также библиотека stringio
.
Интерфейс класса StringIO
практически такой же, как в первом издании этой книги. В нем есть метод доступа string
, ссылающийся на содержимое самой строки.
require 'stringio'
ios = StringIO.new('abcdefghijkl
ABC
123')
ios.seek(5)
ios.puts('xyz')
puts ios.tell # 8
puts ios.string.dump # 'abcdexyzijkl
ABC
123'