В маске, описывающей режим файла, можно устанавливать или сбрасывать некоторые биты. Они не имеют прямого отношения к битам, обсуждавшимся в разделе 10.1.9. Речь идет о битах set-group-id, set-user-id и бите фиксации (sticky bit). Для каждого из них есть метод в модуле
FileTest
.
file = File.new("somefile")
info = file.stat
sticky_flag = info.sticky?
setgid_flag = info.setgid?
setuid_flag = info.setuid?
К
дисковому файлу могут вести символические или физические ссылки (в тех операционных системах, где такой механизм поддерживается). Чтобы проверить, является ли файл символической ссылкой на другой файл, обратитесь к методу
symlink?
из модуля
FileTest
. Для подсчета числа физических ссылок на файл служит метод
nlink
(он есть только в классе
File::Stat
). Физическая ссылка неотличима от обычного файла — это просто файл, для которого есть несколько имен и записей в каталоге.
File.symlink("yourfile","myfile") # Создать ссылку
is_sym = FileTest::symlink?("myfile") # true
hard_count = File.new("myfile").stat.nlink # 0
Отметим попутно, что в предыдущем примере мы воспользовались методом класса
symlink
из класса
File
для создания символической ссылки.
В редких случаях может понадобиться информация о файле еще более низкого уровня. В классе
File::Stat
есть еще три метода экземпляра, предоставляющих такую информацию. Метод
dev
возвращает целое число, идентифицирующее устройство, на котором расположен файл. Метод
rdev
возвращает целое число, описывающее тип устройства, а для дисковых файлов метод
ino
возвращает номер первого индексного узла, занятого файлом.
file = File.new("diskfile")
info = file.stat
device = info.dev
devtype = info.rdev
inode = info.ino
10.1.13. Каналы
Ruby поддерживает разные способы читать из канала и писать в него. Метод класса
IO.popen
открывает канал и связывает с возвращенным объектом стандартные ввод и вывод процесса. Часто с разными концами канала работают разные потоки, но в примере ниже запись и чтение осуществляет один и тот же поток:
check = IO.popen("spell","r+")
check.puts("'T was brillig, and the slithy toves")
check.puts("Did gyre and gimble in the wabe.")
check.close_write
list = check.readlines
list.collect! { |x| x.chomp }
# list равно %w[brillig gimble gyre slithy toves wabe]
Отметим, что вызов
close_write
обязателен, иначе мы никогда не достигнем конца файла при чтении из канала. Существует также блочная форма:
File.popen("/usr/games/fortune") do |pipe|
quote = pipe.gets
puts quote
#
На чистом диске можно искать бесконечно. – Том Стил.
end
Если задана строка
"-"
, то запускается новый экземпляр Ruby. Если при этом задан еще и блок, то он работает в двух разных процессах, как в результате разветвления (fork); блоку в процессе-потомке передается
nil
, а в процессе-родителе — объект
IO
, с которым связан стандартный ввод или стандартный вывод.
IO.popen("-")
do |mypipe|
if mypipe
puts "Я родитель: pid = #{Process.pid}"
listen = mypipe.gets
puts listen
else
puts "Я потомок: pid = #{Process.pid}"
end
end
# Печатается:
# Я родитель: pid = 10580
# Я потомок: pid = 10582
Метод
pipe
возвращает также два конца канала, связанных между собой. В следующем примере мы создаем два потока, один из которых передает сообщение другому (то самое сообщение, которое Сэмюэль Морзе впервые послал по телеграфу). Если вы не знаете, что такое потоки, обратитесь к главе 3.
pipe = IO.pipe
reader = pipe[0]
writer = pipe[1]
str = nil
thread1 = Thread.new(reader,writer) do |reader,writer|
# writer.close_write
str = reader.gets
reader.close
end
thread2 = Thread.new(reader,writer) do |reader,writer|
# reader.close_read
writer.puts("What hath God wrought?")
writer.close
end
thread1.join
thread2.join
puts str # What hath God wrought?
10.1.14. Специальные операции ввода/вывода
В Ruby можно выполнять низкоуровневые операции ввода/вывода. Мы только упомянем о существовании таких методов; если вы собираетесь ими пользоваться, имейте в виду, что некоторые машиннозависимы (различаются даже в разных версиях UNIX).
Метод
ioctl
принимает два аргумента: целое число, определяющее операцию, и целое число либо строку, представляющую параметр этой операции.
Метод
fcntl
также предназначен для низкоуровневого управления файловыми потоками системно зависимым образом. Он принимает такие же параметры, как