С вопросом о том, существует ли файл, связан другой вопрос: а есть ли в нем какие-нибудь данные? Ведь файл может существовать, но иметь нулевую длину — а это практически равносильно тому, что он отсутствует.
Если нас интересует только, пуст ли файл, то в классе File::Stat
есть два метода экземпляра, отвечающих на этот вопрос. Метод zero?
возвращает true
, если длина файла равна нулю, и false
в противном случае.
flag = File.new('somefile').stat.zero?
Метод size?
возвращает либо размер файла в байтах, если он больше нуля, либо nil для файла нулевой длины. Не сразу понятно, почему nil
, а не 0. Дело в том, что метод предполагалось использовать в качестве предиката, а значение истинности нуля в Ruby — true
, тогда как для nil
оно равно false
.
if File.new('myfile').stat.size?
puts 'В файле есть данные.'
else
puts 'Файл пуст.'
end
Методы zero?
и size?
включены также в модуль FileTest
:
flag1 = FileTest::zero?('file1')
flag2 = FileTest::size?('file2')
Далее возникает следующий вопрос: «Каков размер файла?» Мы уже видели что для непустого файла метод size?
возвращает длину. Но если мы применяем его не в качестве предиката, то значение nil
только путает.
В классе File
есть метод класса (но не метод экземпляра) для ответа на этот вопрос. Метод экземпляра с таким же именем имеется в классе File::Stat
.
size1 = File.size('file1')
size2 = File.stat('file2').size
Чтобы получить размер файла в блоках, а не в байтах, можно обратиться к методу blocks
из класса File::Stat
. Результат, конечно, зависит от операционной системы. (Метод blksize
сообщает размер блока операционной системы.)
info = File.stat('somefile')
total_bytes = info.blocks * info.blksize
10.1.12. Опрос специальных свойств файла
У файла есть много свойств, которые можно опросить. Мы перечислим в этом разделе те встроенные методы, для которых не нашлось другого места. Почти все они являются предикатами.
Читая этот раздел (да и большую часть этой главы), помните о двух вещах. Во-первых, так как класс File
подмешивает модуль FileTest
, то любую проверку, для которой требуется вызывать метод, квалифицированный именем модуля, можно также выполнить, обратившись к методу экземпляра любого файлового объекта. Во-вторых, функциональность модуля FileTest
и объекта File::Stat
(возвращаемого методом stat
или lstat
) сильно перекрывается. В некоторых случаях есть целых три разных способа вызвать по сути один и тот же метод. Мы не будем каждый раз приводить все варианты.
В некоторых операционных системах устройства подразделяются на блочные и символьные. Файл может ссылаться как на то, так и на другое, но не на оба сразу. Методы blockdev?
и chardev?
из модуля FileTest
проверяют тип устройства:
flag1 = FileTest::chardev?('/dev/hdisk0') # false
flag2 = FileTest::blockdev?('/dev/hdisk0') # true
Иногда нужно знать, ассоциирован ли данный поток с терминалом. Метод tty?
класса IO
(синоним isatty
) дает ответ на этот вопрос:
flag1 = STDIN.tty? # true
flag2 = File.new('diskfile').isatty # false
Поток может быть связан с каналом (pipe) или сокетом. В модуле FileTest
есть методы для опроса этих условий:
flag1 = FileTest::pipe?(myfile)
flag2 = FileTest::socket?(myfile)
Напомним, что каталог — это разновидность файла. Поэтому нужно уметь отличать каталоги от обычных файлов, для чего предназначены два метода из модуля FileTest
:
file1 = File.new('/tmp')
file2 = File.new('/tmp/myfile')
test1 = file1.directory? # true
test2 = file1.file? # false
test3 = file2.directory? # false
test4 = file2.file? # true
В классе File
есть также метод класса ftype
, который сообщает вид потока; одноименный метод экземпляра находится в классе File::Stat
. Этот метод возвращает одну из следующих строк: file
, directory
, blockSpecial
, characterSpecial
, fifo
, link
или socket
(строка fifо
относится к каналу).
this_kind = File.ftype('/dev/hdisk0') # 'blockSpecial'
that_kind = File.new('/tmp').stat.ftype # 'directory'
В маске, описывающей режим файла, можно устанавливать или сбрасывать некоторые биты. Они не имеют прямого отношения к битам, обсуждавшимся в разделе 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')