# А при таком способе более экономно расходуется память:
while ! ARGF.eof?
puts ARGF.readline
end
# Пример: ruby cat.rb file1 file2 file3
При чтении из стандартного ввода (
stdin
) методы
Kernel
не вызываются. Потому можно обойти (или не обходить)
ARGF
, как показано ниже:
#
Прочитать строку из стандартного ввода.
str1 = STDIN.gets
# Прочитать строку из ARGF.
str2 = ARGF.gets
# А теперь снова из стандартного ввода.
str3 = STDIN.gets
10.1.8. Буферизованный и небуферизованный ввод/вывод
В некоторых случаях Ruby осуществляет буферизацию самостоятельно. Рассмотрим следующий фрагмент:
print "Привет... "
sleep 10
print "Пока!\n"
Если запустить эту программу, то вы увидите, что сообщения «Привет» и «Пока» появляются одновременно, после завершения
sleep
. При этом первое сообщение не завершается символом новой строки.
Это можно исправить, вызвав метод
flush
для опустошения буфера вывода. В данном случае вывод идет в поток
$defout
(подразумеваемый по умолчанию для всех методов
Kernel
, которые занимаются выводом). И поведение оказывается ожидаемым, то есть первое сообщение появляется раньше второго.
print "Привет... "
STDOUT.flush
sleep 10
print "Пока!\n"
Буферизацию можно отключить (или включить) методом
sync=
, а метод
sync
позволяет узнать текущее состояние.
buf_flag = $defout.sync # true
STDOUT.sync = false
buf_flag = STDOUT.sync # false
Есть еще по крайней мере один низкий уровень буферизации, который не виден. Если метод
getc
возвращает символ и продвигает вперед указатель файла или потока, то метод
ungetc
возвращает символ назад в поток.
ch = mystream.getc # ?А
mystream.ungetc(?C)
ch = mystream.getc # ?C
Тут следует иметь в виду три вещи. Во-первых, только что упомянутая буферизация не имеет отношения к механизму буферизации, о котором мы говорили выше в этом разделе. Иными словами, предложение
sync=false
не отключает ее. Во-вторых, вернуть в поток можно только один символ; при попытке вызвать метод
ungetc
несколько раз будет возвращен только символ, прочитанный последним. И, в-третьих, метод
ungetc
не работает для принципиально небуферизуемых операций (например,
sysread
).
10.1.9. Манипулирование правами владения и разрешениями на доступ к файлу
Вопрос о владении файлами и разрешениях сильно зависит от платформы. Как правило, в системе UNIX функций больше, чем предоставляет Ruby, а на других платформах многие возможности
не реализованы.
Для определения владельца и группы файла (это целые числа) класс
File::Stat
предоставляет методы экземпляра
uid
и
gid
:
data = File.stat("somefile")
owner_id = data.uid
group_id = data.gid
В классе
File::Stat
есть также метод экземпляра mode, который возвращает текущий набор разрешений для файла.
perms = File.stat("somefile").mode
В классе
File
имеется метод класса и экземпляра
chown
, позволяющий изменить идентификаторы владельца и группы. Метод класса принимает произвольное число файлов. Если идентификатор не нужно изменять, можно передать
nil
или -1.
uid = 201
gid = 10
File.chown(uid, gid, "alpha", "beta")
f1 = File.new("delta")
f1.chown(uid, gid)
f2 = File.new("gamma")
f2.chown(nil, gid) # Оставить идентификатор владельца без изменения.
Разрешения можно изменить с помощью метода
chmod
(у него также есть два варианта: метод класса и метод экземпляра). Традиционно разрешения представляют восьмеричным числом, хотя это и не обязательно.
File.chmod(0644, "epsilon", "theta")
f = File.new("eta")
f.chmod(0444)
Процесс всегда работает от имени какого-то пользователя (возможно,
root
), поэтому с ним связан идентификатор пользователя (мы сейчас говорим о действующем идентификаторе). Часто нужно знать, имеет ли данный пользователь право читать, писать или исполнять данный файл. В классе
File::Stat
есть методы экземпляра для получения такой информации.
info = File.stat("/tmp/secrets")
rflag = info.readable?
wflag = info.writable?
xflag = info.executable?
Иногда нужно отличить действующий идентификатор пользователя от реального. На этот случай предлагаются методы экземпляра
readable_real?
,
writable_real?
и
executable_real?
.
info = File.stat("/tmp/secrets")
rflag2 = info.readable_real?
wflag2 = info.writable_real?
xflag2 = info.executable_real?
Можно сравнить владельца файла с действующим идентификатором пользователя (и идентификатором группы) текущего процесса. В классе
File::Stat
для этого есть методы
owned?
и
grpowned?
.
Отметим, что многие из этих методов можно найти также в модуле