Для изменения времени доступа и модификации применяется метод
utime
, которому можно передать несколько файлов. Время можно создать в виде объекта
Time
или числа секунд, прошедших с точки отсчета.
today = Time.now
yesterday = today - 86400
File.utime(today, today, "alpha")
File.utime(today, yesterday, "beta", "gamma")
Поскольку оба временных штампа изменяются одновременно, то при желании оставить один без изменения его сначала следует получить и сохранить.
mtime = File.mtime("delta")
File.utime(Time.now, mtime, "delta")
10.1.11.
Проверка существования и получение размера файла
Часто необходимо знать, существует ли файл с данным именем. Это позволяет выяснить метод
exist?
из модуля
FileTest
:
flag = FileTest::exist?("LochNessMonster")
flag = FileTest::exists?("UFO")
# exists? является синонимом exist?
Понятно, что такой метод не может быть методом экземпляра
File
, поскольку после создания объекта файл уже открыт. В классе
File
мог бы быть метод класса с именем
exist?
, но его там нет.
С вопросом о том, существует ли файл, связан другой вопрос: а есть ли в нем какие-нибудь данные? Ведь файл может существовать, но иметь нулевую длину — а это практически равносильно тому, что он отсутствует.
Если нас интересует только, пуст ли файл, то в классе
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
, который сообщает вид потока; одноименный метод экземпляра находится в классе