Первый сайт на Perl

         

Операции с файлами

Перед изучением функций, выполняющих действия с целыми файлами, мы напомним читателю основные положения, связанные с организацией файловой системы UNIX и процедур доступа к файлам. Функции Perl разрабатывались для работы именно с этой файловой системой, хотя в определенной степени многое из того, о чем пойдет речь, применимо и к файловым системам других платформ.

Работа пользователя в UNIX начинается с процедуры регистрации в системе, во время которой он вводит свое регистрационное имя и пароль. Регистрационное имя назначается администратором системы и хранится в специальном учетном файле. Пароль задает сам пользователь.

Регистрационное имя легко запоминается пользователем, но для системы удобнее вести учет пользователей, идентифицируя их не по символическим регистрационным именам, а по числовым идентификаторам. Поэтому каждому пользователю системы UNIX помимо мнемонического регистрационного имени присваивается также числовой идентификатор пользователя (uid — User IDentifier) и идентификатор группы (gid — Group IDentifier), к которой он относится. Значения uid и gid приписываются процессу, в котором выполняется командный интерпретатор shell, запускаемый при входе пользователя в систему. Эти же идентификаторы передаются и любому другому процессу, запускаемому пользователем во время его сеанса работы в UNIX.

Файловая система UNIX представляет собой дерево, промежуточные вершины которого соответствуют каталогам, а листья файлам или пустым каталогам. Каждый файл идентифицируется своим уникальным полным именем, которое включает в себя полный путь (pathname) от корня файловой системы через промежуточные вершины (каталоги) непосредственно к файлу. Корневой каталог имеет предопределенное имя, представляемое символом "/". Этот же символ используется и для разделения имен каталогов в цепочке полного имени файла, например /bin/prog.exe.

Каждый файл в файловой системе UNIX характеризуется значительно большим объемом информации, чем, например, файл в файловой системе FAT. Эта информация включает, в частности, данные о владельце файла, группе, к которой принадлежит владелец файла, о том, кто имеет право на чтение файла, запись в файл, на выполнение файла и т. д. Эта информация позволяет задавать разные права доступа к файлу для следующих категорий пользователей: владелец файла, члены группы владельца, прочие пользователи. Вся существенная информация о файле хранится в специальной структуре данных, называемой индексным дескриптором (mode). Индексные дескрипторы размещаются в специальной области диска, формируемой при его форматировании в системе UNIX.

При запуске процесса с ним связываются два идентификатора пользователя: действительный (real) и эффективный (effective) и два аналогичных идентификатора группы пользователей. Действительные идентификаторы пользователя и группы — это постоянные идентификаторы, связываемые со всеми процессами, запускаемыми пользователем. Эффективные идентификаторы — это временные идентификаторы, которые могут устанавливаться для выполнения определенных действий. Например, при изменении пользователем пароля программа passwd автоматически устанавливает эффективные идентификаторы процесса таким образом, чтобы обеспечить права записи в файл паролей.

Как только с процессом связаны соответствующие идентификаторы, для него начинают действовать ограничения доступа к файлам. Процесс может получить доступ к файлу только в случае, если это позволяют хранящиеся при файле ограничения доступа.

Для каждого зарегистрированного пользователя системы создается так называемый "домашний" (home) каталог пользователя, к которому он имеет неограниченный доступ, а также и ко всем каталогам и файлам, содержащимся в нем. Пользователь может создавать, удалять и модифицировать каталоги и файлы из своего домашнего каталога. Потенциально возможен доступ и ко всем другим файлам, однако он может быть ограничен, если пользователь не имеет достаточных привилегий.

Любой пользователь, создавший собственный файл, считается его владельцем. Изменить владельца файла из сценария Perl можно функцией chown (). Параметром этой функции является список, первые два элемента которого должны представлять новые .числовые идентификаторы uid и gid. Остальные элементы списка являются именами файлов, для которых изменяется владелец. Эта функция возвращает количество файлов, для которых операция изменения владельца и группы прошла успешно.

@list = ( 234, 3, "filel.dat", "file2.dat");

$number = chown(@list);

warn "Изменился владелец не у всех файлов!" if $number != @list-2;

Замечание

Изменить владельца файла может только сам владелец или суперпользователь (обычно системный администратор) системы UNIX. В операционных системах с файловой системой отличной от UNIX (DOS, Windows) эта функция отрабатывает, но ее установки не влияют на доступ к файлу.

Функция chmodo изменяет права доступа для файлов, представленных в списке, передаваемом ей в качестве параметра. Первым элементом этого списка должно быть трехзначное восьмеричное число, задающее права доступа для владельца, пользователей из группы, в которую входит владелец, и прочих пользователей. Каждая восьмеричная цифра определяет право на чтение файла, запись в файл и его выполнение (в случае если файл представляет выполняемую программу) для указанных выше групп пользователей. Установленные биты ее двоичного представления отражают соответствующие права доступа к файлу. Например, если установлены все три бита (восьмеричное число 7), то соответствующая группа пользователей обладает всеми перечисленными правами: может читать из файла, записывать в файл и выполнять его. Значение равное 6 определяет право на чтение и запись, 5 позволяет читать из файла, выполнять его, но не позволяет записывать в этот файл и т. д. Обычно не выполняемый файл создается с режимом доступа 0666 — все пользователи могут читать и записывать информацию в файл, выполняемый файл — с режимом 0777. Если владелец файла желает ограничить запись в файл пользователей не его группы, то следует выполнить следующий оператор:

chmod 0664, "file.dat";

Возвращаемым значением функции chmodo, как и функции chowno, является количество файлов из списка, для которых операция изменения прав доступа завершилась успешно.

Замечание

В операционных системах DOS и Windows имеет значение только установка режимов доступа владельца.

В структуре индексного дескриптора файла существует три поля, в которых хранится время последнего обращения (atime) к файлу, его изменения (mtime) файла и изменения индексного дескриптора Xctime): Функцией utimeO можно изменить время последнего обращения и модификации файла. Ее параметром является список, содержащий имена обрабатываемых файлов, причем первые два элемента списка — числовые значения нового времени последнего доступа и модификации:

gfiles = ("filel.dat", "file2.dat");

$now = time;

utime $now, $now, 6files;

В этом фрагменте кода время последнего доступа и модификации файлов из списка @files изменяется на текущее время, полученное с помощью функции time.

Отметим, что при выполнении функции utime о изменяется и время последней модификации индексного дескриптора (ctime) — оно устанавливается равным текущему времени. Возвращаемым значением является количе- . ство файлов, для которых операция изменения времени последнего доступа и модификации прошла успешно.

Файловая система UNIX позволяет создавать ссылки на один и тот же файл. Это реализуется простым указанием одного и того же индексного дескриптора для двух элементов каталога. Такие ссылки называются жесткими (hard) ссылками, и операционная система не различает элемент каталога, созданный при создании файла, и ссылок на этот файл. При обращении к файлу по ссылке и по имени изменяются поля индексного дескриптора. Физически файл уничтожается только тогда, когда уничтожается последняя жесткая ссылка на файл.

В UNIX существует еще один тип ссылок на файл — символические ссылки. Эти ссылки отличаются от жестких тем, что они косвенно ссылаются на файл, имя которого хранится в блоке данных символической ссылки.

Жесткие ссылки создаются в Perl функцией linko, а символические — функцией symiinko. Синтаксис этих функций одинаков — их два параметра представляют имя файла, для которого создается ссылка, и новое имя файла-ссылки:

link СТАРЫЙ_ФАЙЛ, НОВЫЙ_ФАЙЛ; symlink СТАРЫЙ_ФАЙД, НОВЫЙ_ФАЙЛ;

При успешном создании жесткой ссылки функция link о возвращает Истина, иначе Ложь. Создание символической ссылки функцией symiinko сопровождается возвратом ею числа i в случае успешного выполнения операции иов противном случае.

Замечание

В версиях Peri для DOS эти функции не реализованы, и при попытке их вызова интерпретатор выдает фатальную ошибку:

The Unsupported function link function is unimplemented at D:\EX2.PL line 2.

The symlink function is unimplemented at D:\EX2.PL line 2.

Удалить существующие ссылки на файл можно функцией unlink о. Эта функция удаляет одну ссылку на каждый файл, заданный в списке ее параметров. Если ссылок на файл не существует, то удаляется сам файл. Функция возвращает количество файлов, для которых успешно прошла операция удаления. Вызов функции unlink без списка параметров использует содержимое специальной переменной $_ в качестве списка параметров. Следующий фрагмент кода удаляет все резервные копии файлов текущего каталога:

unlink <*.bak>;

В структуре индексного дескриптора поле nlink содержит количество жестких ссылок на файл. Его можно использовать совместно с функцией unlink о для удаления всех ссылок на файл. Если ссылок нет, то это поле имеет значение 1 (только имя файла, определенное при его создании, ссылается на индексный дескриптор файла).

Замечание

Каталоги в UNIX являются файлами специального вида. Однако их нельзя удалить функцией unlink, если только вы не суперпользователь или при запуске peri не используется флаг -и. Для удаления каталогов рекомендуется использовать функцию rmdir ().

Две последние операции, связанные с файлами, — это переименование и усечение файла. Функция rename о меняет имя файла, заданного первым параметром, на имя, определяемое вторым параметром этой функции:

rename "old.dat", "new.dat";

Этот оператор переименует файл old.dat в файл new.dat. Функция переименования файла возвращает i при успешном выполнении этой операции и о в противном случае.

Функция truncated усекает файл до заданной длины. Для задания файла можно использовать как имя файла, так и дескриптор открытого файла:

truncate ДЕСКРИПТОР, ДЛИНА; truncate ИМЯ_ФАЙЛА, ДЛИНА;

Функция возвращает значение Истина, если длина файла успешно усечена до количества байт, определенных в параметре ДЛИНА, или неопределенное значение undef в противном случае. Под усечением файла понимается не только уменьшение его длины, но и увеличение. Это означает, что значение второго параметра функции truncate о может быть больше истинной длины файла, что позволяет делать "дыры" в содержимом файла, которые в дальнейшем можно использовать для записи необходимой информации, не уничтожая уже записанную в файл (пример 7.7).

#! peri -w

# Создание файла с "дырами" for($i=l;$i<=3;$i++H

open(F, "»out.dat") or die $!; print F "Запись".$i;

close F;

open(F, "»out.dat") or die $!; truncate F, 19*$i;

close F;

} ' tt Запись информации в "дыры" open(F, "+<out.dat") or die $!; for($i=l;$i<=3;$i++){

seek F, 0,1;

read F,$reel,7;

seek F,0,l;

print F "<CONTENTS:".$i.">"; } close F;

На каждом шаге первого цикла for примера 7.7 в конец файла out.dat записывается информация длиной 7 байтов, а потом его длина увеличивается на 12 байтов, образуя пустое пространство в файле. Следующий цикл for заносит в эти созданные "дыры" информацию длиной 12 байтов, не затирая хранящуюся в файле информацию. Обратите внимание, что для изменения длины файла функцией truncate приходится закрывать его и снова открывать. Это связано с тем обстоятельством, что функция truncate о добавляет пустое пространство в начало файла, сдвигая в конец его содержимое, если применять ее, не закрывая файл. Можете поэкспериментировать с программой примера 7.7, открыв файл перед выполнением первого цикла for, и закрыв его после завершения цикла. Содержимое файла даст вам наглядное представление о работе функции truncate в этом случае. У нас же после выполнения первого цикла for содержимое файла out.dat выглядит так:

Запись1 Запись2 Запись3

\

По завершении всей программы файл будет содержать следующую строку:

Запись<CONTENTS:1>Запись2<CONTENTS:2>ЗаписьЗ<CONTENTS:3>

Содержание раздела