HTML page
|
Доступ к файлам
Введение
Файлы занимают центральное место в обработке данных. Как и во всем остальном в Perl, простые операции с файлами выполняются просто, а сложные... как-нибудь да выполняются. Стандартные задачи (открытие файлов, чтение данных, запись данных) используют простые функции ввода/вывода и операторы, а более экзотические функции способны даже на асинхронный ввод/вывод и блокировку (locking) файлов. В этой главе рассматривается механика доступа к файлам: открытие файлов, передача сведений о том, с какими файлами вы собираетесь работать, блокировка и т. д. Глава 8 «Содержимое файлов» посвящена работе с содержимым файлов: чтению, записи, перестановке строк и другим операциям, которые становятся возможными после получения доступа к файлу. Следующий фрагмент выводит все строки файла /usr/local/widgets/data, содержащие слово "blue":open (INPUT, "< /usr/local/widgets/data")
or die "Couldn't open /usr/local/widgets/data for reading: $!\n";
while (INPUT) {
print if /blue/, } close(INPUT); Получение файлового манипулятора Доступ к файлам в Perl организуется при помощи файловых манипуляторов (filehandle) - таких, как INPUT из предыдущего примера. Манипулятор - это символическое имя, которое представляет файл в операциях чтения/записи. Файло- вые манипуляторы не являются переменными. В их именах отсутствуют префиксы $, @ или %, однако они наряду с функциями и переменными попадают в символьную таблицу Perl. По этой причине не всегда удается сохранить файловый манипулятор в переменной или передать его функции. Приходится использовать префикс *, который является признаком тип-глоба - базовой единицы символьной таблицы Perl:
$var = *STDIN;
my sub($var, *LOGFILE); Файловые манипуляторы, сохраняемые в переменных подобным образом, не используются напрямую. Они называются косвенными файловыми манипуляторами (indirect filehandle), поскольку косвенно ссылаются на настоящие манипуляторы. Два модуля, IO::File (стал стандартным, начиная с версии 5.004) и FileHandle (стандартный с версии 5.000), могут создавать анонимные файловые манипуляторы. Когда в наших примерах используются модули IO::File или IO::Handle, аналогичные результаты можно получить с применением модуля FileHandle, поскольку сейчас он является интерфейсным модулем (wrapper). Ниже показано, как выглядит программа для поиска "blue" с применением модуля IO::File в чисто объектной записи:
use 10::File:
$input = 10::File->new("< /usr/local/widgets/data")
or die "Couldn't open /usr/local/widgets/data for reading: $!\n":
while (defined($line = $input->getline())) {
chomp($line);
STDOUT->print($line) if $line =~ /blue/;
} $input->close();
Как видите, без прямого использования файловых манипуляторов программа
читается намного легче. Кроме того, она гораздо быстрее работает. Но поделимся
одним секретом: из этой программы можно выкинуть все стрелки и вызовы
методов. В отличие от большинства объектов, объекты IO::File не обязательно
использовать объектно-ориентированным способом. В сущности, они представляют
собой анонимные файловые манипуляторы и потому могут использоваться везде,
где допускаются обычные косвенные манипуляторы. В рецепте 7.16 рассматриваются
эти модули и префикс *. Модуль IO::File и символические файловые манипуляторы
неоднократно встречаются в этой главе. Стандартные файловые манипуляторы
Каждая программа при запуске получает три открытых глобальных файловых
манипулятора: STDIN, STDOUT и STDERR. STDIN {стандартный ввод) является
источником входных данных по умолчанию. В STDOUT {стандартный вывод) по
умолчанию направляются выходные данные. В STDERR {стандартный поток ошибок)
по умолчанию направляются предупреждения и ошибки. В интер- активных программах
STDIN соответствует клавиатуре, a STDOUT и STDERR - экрану монитора:
while(
unless (/\d/) {
warn "No digit found.\n"; # Вывод в STDERR
}
print "Read: ", $_; # Запись в STDOUT
} END { close(STDOUT) or die "couldn't close STDOUT: $!" } Файловые
манипуляторы существуют на уровне пакетов. Это позволяет двум пакетам иметь
разные файловые манипуляторы с одинаковыми именами (по аналогии с функциями
и переменными). Функция open связывает 4)айловый манипулятор с файлом
или программой, после чего его можно использовать для ввода/ вывода. После
завершения работы вызовите для манипулятора функцию close, чтобы разорвать
установленную связь. Операционная система работает с файлами через файловые
дескрипторы, значение которых определяется функцией fileno. Для большинства
файловых операций хватает манипуляторов Perl, однако в рецепте 7.19 показано,
как файловый дескриптор преобразуется в файловый манипулятор, используемый
в программе. Операции ввода/вывода Основные функции для работы с файлами
в Perl - open, print, <...> (чтение записи) и close. Они представляют
собой интерфейсные функции для процедур буферизованной библиотеки ввода/вывода
С stdio. Функции ввода/вывода Perl документированы в perlfunc( 1) и страницах
руководства stdio(3S) вашей системы. В следующей главе операции ввода/вывода
- такие, как оператор> о, print, seek и tell - рассматриваются более подробно.
Важнейшей .функцией ввода/вывода является функция open. Она получает два
аргумента - файловый манипулятор и строку с именем файла и режимом доступа.
Например, открытие файла /tmp/log для записи и его связывание с манипулятором
LOG FILE выполняется следующей командой:
open(LOGFILE, "> /tmp/log") or die "Can't write /tmp/log: $!";
Три основных режима доступа - < (чтение), > (запись) и » (добавление).
Дополнительные сведения о функции open приведены в рецепте 7.1. При открытии
файла или вызове практически любой системной функции* необходимо проверять
возвращаемое значение. Не каждый вызов open заканчивается успешно; не
каждый файл удается прочитать; не каждый фрагмент данных, выводимый функцией
print, достигает места назначения. Многие программисты для повышения устойчивости
своих программ проверяют результаты open, seek, tell и close. Иногда приходится
вызывать и другие функции. В документации Perl описаны возвращаемые значения
всех функций и операторов. При неудачном завершении системная функция
возвращает undef (кроме функций wait, waitpid и Системной функцией называется
обращение к сервису операционной системы. Термин не имеет отношения к
функции system в языках С и Perl.
syscall, возвращающих -1). Системное сообщение или код ошибки хранится
в переменной $1 и часто используется в die или сообщениях warn. Для чтения
записей в Perl применяется оператор <МАНИПУЛЯТОР>, также часто дублируемый
функцией readllne. Обычно запись представляет собой одну строку, однако
разделитель записей можно изменить (см. главу 8). Если МАНИПУЛЯТОР не указывается,
Perl открывает и читает файлы из @ARGV, а если они не указаны - из STDIN.
Нестандартные и просто любопытные применения этого факта описаны в рецепте
7.7. С абстрактной точки зрения файл представляет собой обычный поток байтов.
Каждый файловый манипулятор ассоциируется с числом, определяющим текущую
позицию внутри файла. Текущая позиция возвращается функцией tell и устанавливается
функцией seek. В рецепте 7.10 мы перезаписываем файл, обходясь без закрытия
и повторного открытия, - для этого мы возвращаемся к началу файла функцией
seek. Когда надобность в файловом манипуляторе отпадает, закройте его функцией
close. Функция получает один аргумент (файловый манипулятор) и возвращает
true, если буфер был успешно очищен, а файл - закрыт, и false в противном
случае. Закрывать все манипуляторы функцией close необязательно. При открытии
файла, который был открыт ранее, Perl сначала неявно закрывает его. Кроме
того, все открытые файловые манипуляторы закрываются при завершении программы.
Неявное закрытие файлов реализовано для удобства, а не для повышения надежности,
поскольку вы не узнаете, успешно ли завершилась системная функция. Не все
попытки закрытия завершаются успешно. Даже если файл открыт только для
чтения, вызов close может завершиться неудачей - например, если доступ
к устройству был утрачен из-за сбоя сети. Еще важнее проверять результат
close, если файл был открыт для записи, иначе можно просто не заметить
переполнения диска:
close(FH) or die "FH didn't close: $!"; Усердный программист даже проверяет
результат вызова close для STDOUT в конце программы на случай, если выходные
данные были перенаправлены в командной строке, а выходная файловая система
оказалась переполнена. Вообще-то об этом должна заботиться runtime-система,
но она этого не делает. Впрочем, проверка STDERR выглядит сомнительно.
Даже если этот поток не закроется, как вы собираетесь на это реагировать?
Манипулятор STDOUT по умолчанию используется для вывода данных функциями
print, printf и write. Его можно заменить функцией select, которая получает
новый и возвращает предыдущий выходной манипулятор, используемый по умолчанию.
Перед вызовом select должен быть открыт новый манипулятор вывода:
$old_fh = select(LOGFILE); # Переключить вывод на LOGFILE print
"Countdown initiated ...\n";
select($old_fh); # Вернуться к выводу на прежний манипулятор
print "You have 30 seconds to reach minumum safety distance.\n";
Некоторые
специальные переменные Perl изменяют поведение текущего файлового манипулятора
вывода. Особенно важна переменная $ |, которая управляет буферизацией вывода
для файловых манипуляторов. Буферизация рассматривается в рецепте 7.12.
Функции ввода/вывода в Perl делятся на буферизованные и небуферизованные
(табл. 7.1). Несмотря на отдельные исключения, не следует чередовать их
вызовы в программе. Связь между функциями, находящимися в одной строке
таблицы, весьма условна. Например, но семантике функция sys read отличается
от <. . , >, однако они находятся в одной строке, поскольку выполняют
общую задачу - получение входных данных из файлового манипулятора. Таблица
7.1 Функции ввода/вывода в Perl Действие Буферизованные функции Небуферизованные
функции Открытие open,sysopen sysopen Закрытие close close Ввод <...>,
readline sysread Вывод print syswrite Позиционирование seek, tell__________
sysseek ___ ___ Позиционирование рассматривается в главе 8, однако мы также
воспользуемся им в рецепте 7.10.
7.1. Открытие файла
Проблема
Известно имя файла. Требуется открыть его для чтения или записи в Perl.Решение
Функция open отличается удобством, sysopen - точностью, а модуль IO::File позволяет работать с анонимным файловым манипулятором. Функция open получает два аргумента: открываемый файловый манипулятор и строку с именем файла и специальными символами, определяющими режим открытия:open(SOURCE, "< $path")
or die "Couldn't open $path for reading: $!\n";
open(SINK, "> $path")
or die "Couldn't open $path for writing: $!\n";
где SOURCE - файловый манипулятор для ввода, a SINK - для вывода. Функции sysopen передаются три или четыре аргумента: файловый манипулятор, имя файла, режим и необязательный параметр, определяющий права доступа. Режим представляет собой число, конструируемое из констант модуля Fcnti:
use Fcnti;
sysopen(SOURCE, $path, O.RDONLY)
or die "Couldn't open $path for reading: $!\n";
sysopen(SINK, $path, 0_WRONLY)
or die "Couldn't open $path for writing: $!\n"; Аргументы метода new модуля IO::File могут задаваться в стиле как open, так и sysopen. Метод возвращает анонимный файловый манипулятор. Кроме того, также возможно задание режима открытия в стиле fopen(3):
use 10::File; # По аналогии с
open $sink = 10::File->new("> $filename")
or die "Couldn't open $filename for writing: $!\n";
# По аналогии с sysopen
$fh = 10::File->new($filename, 0_WRONLY|0_CREAT)
or die "Couldn't open $filename for reading: $!\n";
# По аналогии с fopen(3) библиотеки
stdio $fh = 10::File->new($filename, "r+")
or die "Couldn't open $filename for read and write: $!\n";
Комментарий
Все операции ввода/вывода осуществляются через файловые манипуляторы независимо от того, упоминаются манипуляторы в программе или нет. Файловые манипуляторы не всегда связаны с конкретными файлами - они также применяются для взаимодействия с другими программами (см. главу 16 «Управление процессами и межпроцессные взаимодействия») и в сетевых коммуникациях (см. главу 17 «Сокеты»). Функция open также применяется для работы с файловыми дескрипторами, данная возможность рассматривается в рецепте 7.19. Функция open позволяет быстро и удобно связать файловый манипулятор с файлом. Вместе с именем файла передаются сокращенные обозначения стандартных режимов (чтение, запись, чтение/запись, присоединение). Функция не позволяет задать права доступа для создаваемых файлов и вообще решить, нужно ли создавать файл. Если вам потребуются подобные возможности, воспользуйтесь функцией sysopen, которая использует константы модуля Fcnti для управления отдельными компонентами режима (чтение, запись, создание и усечение). Большинство программистов начинает работать с open задолго до первого использования sysopen. В таблице показано соответствие между режимами функции open («Файл»), константами sysopen («Флаги») и строками fopen(3), передаваемыми 10: :File->new («Символы»). Столбцы «Чтение» и «Запись» показывают, возможно ли чтение или запись для данного файлового манипулятора. «Присоединение» означает, что выходные данные всегда направляются в конец файла независимо от текущей позиции (в большинстве систем). В режиме усечения функция open уничтожает все существующие данные в открываемом файле.
7.1.
Открытие файла 245
|
|||||||
Файл
|
Чтение
|
Запись
|
Присое
|
Созда
|
Очистка
|
Флаги
|
Символы
|
|
|
|
динение
|
ние
|
содержи
|
0
|
|
|
|
|
|
|
мого
|
|
|
•
< файл
|
Да
|
Нет
|
Нет
|
Нет
|
Нет
|
RDONLY
|
"г"
|
>
файл,
|
Нет
|
Да
|
Нет
|
Да
|
Да
|
WRONLY
|
"W"
|
режим
|
|
|
|
|
|
TRUNC
|
|
открытия>
|
|
|
|
|
|
CREAT
|
|
»
файл>,
|
Нет
|
Да
|
Да
|
Да
|
Нет
|
WRONLY
|
"а"
|
режим
|
|
|
|
|
|
APPEND
|
|
открытня>
|
|
|
|
|
|
CREAT
|
|
+<
файл
|
Да
|
Да
|
Нет
|
Нет
|
Нет
|
RDWR-
|
"г+"
|
+>
файл,
|
Да
|
Да
|
Нет
|
Да
|
Да
|
RDWR
|
"W+"
|
режим
|
|
|
|
|
|
TRUNC
|
|
открытия>
|
|
|
|
|
|
CREAT
|
|
+»
файл>,
|
Да
|
Да
|
Да
|
Да
|
Нет
|
RDWR
|
"а+"
|
режим
|
|
|
|
|
|
APPEND
|
|
открытия>
|
|
|
|
|
|
CREAT
|
|
Подсказка: режимы +> и +» почти никогда не используются. В первом
случае файл уничтожается еще до того, как он будет прочитан, а во втором
часто возникают затруднения, связанные с тем, что указатель чтения может
находиться в произвольной позиции, но при записи на многих системах почти
всегда происходит переход в конец файла. Функция sysopen получает три
или четыре аргумента:
sysopen(FILEHANDLE, sysopen(FILEHANDLE,
$name, $flags) or die "Can't open $name : $! "; $name, $Hags, Sperms)
or die "Can't open $name : $!"; Здесь $name - имя файла без «довесков»
в виде < или +; $flags - число, полученное объединением констант режимов
0_CREAT, 0_WRONLY, 0_TRUNC и т. д. операцией OR. Конкретный состав доступных
констант 0_ зависит от операционной системы. Дополнительные сведения можно
найти в электронной документации (обычно open (2), но не всегда) или в
файле /usr/include/fcntl.h. Обычно встречаются следующие константы:
0_RDONLY Только чтение.
0_WRONLY Только запись.
0_RDWR Чтение и запись.
0_CREAT Создание файла, если он не существует.
0_EXCL Неудачное завершение, если файл уже существует.
0_APPEND Присоединение к файлу.
0_TRUNC Очистка содержимого файла.
0_NONBLOCK Асинхронный доступ. К числу менее распространенных констант
принадлежат 0_SHLOCK, 0_EXLOCK, 0_BINARY, 0_NOCTTY и 0_SYNC. Обращайтесь
к странице руководства open (2) или к ее эквиваленту. Если функции sysopen
не передается аргумент $perms, Perl использует восьмеричное число 0666.
Права доступа задаются в восьмеричной системе и учитывают текущее значение
маски доступа (задаваемой функцией umask) процесса. В маске доступа сброшенные
биты соответствуют запрещенным правам. Например, если маска равна 027 (группа
не может записывать; прочие не могут читать, записывать или выполнять),
то вызов sysopen с параметром 066 создает файл с правами 0640 (0666&-027
- 0640). Если у вас возникнут затруднения с масками доступа, воспользуйтесь
простым советом: передавайте значение 0666 для обычных файлов и 0777 для
каталогов и исполняемых файлов. У пользователя появляется выбор: если
ему понадобятся защищенные файлы, то может выбрать маску 022, 027 или антиобщественную
маску 077. Как правило, решения из области распределения прав должны приниматься
не программой, а пользователем. Исключения возникают при записи в файлы,
доступ к которым ограничен: почтовые файлы, cookies в Web-броузерах, файлы
.rhosts и т. д. Короче говоря, функция sysopen почти никогда не вызывается
с аргументом 0644, так как у пользователя пропадает возможность выбрать
более либеральную маску. Приведем примеры практического использования open
и sysopen. Открытие файла для чтения:
open(FH, "< $path") or die$!;
sysopen(FH, $path, 0_RDONLY) or die$!;
Открытие файла для записи (если файл не существует, он создается, а
если существует - усекается):
open(FH, "> $path") or die$!;
sysopen(FH, $path, 0_WRONLY|0_TRUNC|0_CREAT) or die$!;
sysopen(FH, $path, 0_WRONLY|0_TRUNC|0_CREAT, 0600) or die$!;
Открытие файла для записи с созданием нового файла (файл не должен
существовать):
sysopen(FH, $path, 0_WRONLY|0_EXCL|0_CREAT) or die$!;
sysopen(FH, $path, 0_WRONLY|0_EXCL|0_CREAT, 0600) or die$!:
Открытие файла для присоединения (в случае необходимости файл создается):
open(FH, "» $path") or die$!; sysopen(FH, $path, 0_WRONLY|0_APPEND|0_CREAT)
or die$!; sysopen(FH, $path, 0_WRONLY|0_APPEND|0_CREAT, 0600) or die$!;
Открытие файла для присоединения (файл должен существовать):
sysopen(FH, $path, 0_WRONLY|0_APPEND) or die$!;
Открытие файла для обновления (файл должен существовать):
open(FH, "+< $path") or die$!;
sysopen(FH, $path, 0_RDWR) or die$!;
Открытие файла для обновления (в случае необходимости файл создается):
sysopen(FH, $path, 0_RDWR|0_CREAT) or die$!;
sysopen(FH, $path, 0_RDWR|0_CREAT, 0600) or die$!;
Открытие файла для обновления (файл не должен существовать):
sysopen(FH, $path, 0_RDWR|0_EXCL|0_CREAT) or die$!;
sysopen(FH, $path, 0_RDWR|0_EXCL|0_CREAT, 0600) or die$!;
Маска 0600 всего лишь поясняет, как создаются файлы с ограниченным
доступом. Обычно этот аргумент пропускается.
Смотри также --------------------------------
Описание функций open, sysopen и umask в perlfunc(1); документация
по стандартным модулям IO::File и Fcnti; страницы руководства open(2),
fopen(3) и umask(2); рецепт 7.2.
7.2. Открытие файлов с нестандартными именами
Проблема
Требуется открыть файл с нестандартным именем - например, "-"; начинающимся с символа <, > или |; содержащим начальные или конечные пропуски; закапчивающимся символом |. Функция open не должна принимать эти функции за служебные, поскольку вам нужно совершенно иное.Решение
Выполните предварительное преобразование:$filename =~ s#"(\s)#./$1#;
open(HANDLE, "< $filename\0") or die "cannot open $filename : $!\n":
Или просто воспользуйтесь функцией sysopen:
sysopen(HANDLE, $filename, 0_RDONLY) or die "cannot open $filename : $!\n";
Комментарий
Функция open определяет имя файла и режим открытия по одному строковому аргументу. Если имя файла начинается с символа, обозначающего один из режимов, open вполне может сделать что-нибудь неожиданное. Рассмотрим следующий фрагмент:$filename = shift @ARGV;
open(INPUT, $filename) or die "cannot open $filename : $!\n":
Если пользователь указывает в командной строке файл ">/etc/passwd", программа попытается открыть /etc/passwd для записи - со всеми вытекающими последствиями! Режим можно задать и явно (например, для записи):
open(OUTPUT, ">$filename")
or die "Couldn't open $filename for writing: $!\n"; но даже в этом случае пользователь может ввести имя ">data", после чего программа будет дописывать данные в конец файла data вместо того, чтобы стереть прежнее содержимое. Самое простое решение - воспользоваться функцией sysopen, у которой режим и имя файла передаются в разных аргументах:
use Fcnti; # Для файловых констант
sysopen(OUTPUT, $filename, 0_WRONLY|0_TRUNC)
or die "Couldn't open $filename for writing: $!\n"; А вот как добиться того же эффекта с функцией open для имен файлов, содержащих начальные или конечные пропуски:
$file =~ зГ(\з)#./$1#;
open(HANDLE, "> $file\0")
or die "Could't open $file for OUTPUT : $!\n"; Такая подстановка защищает исходные пропуски, но не в абсолютных именах типа " /etc/passwd", а лишь в относительных (" passwd"). Функция open не считает нуль-байт ("\0") частью имени файла, но благодаря ему не игнорируются конечные пропуски. Волшебная интерпретация файловых имен в функции open почти всегда оказывается удобной. Вам никогда не приходится обозначать ввод или вывод с помощью особой формы "-". Если написать фильтр и воспользоваться простой функцией open, пользователь сможет передать вместо имени (})айла строку "gzip -de bible. gz |" - фильтр автоматически запустит программу распаковки. Вопросы безопасности open актуальны лишь для программ, работающих в особых условиях. Если программа должна работать под управлением чего-то другого - например, сценариев CGI или со сменой идентификатора пользователя, - добросовестный программист всегда учтет возможность ввода пользователем собственного имени файла, при котором вызов open для простого чтения превратится в перезапись 4)айла или даже запуск другой программы. Параметр командной строки Perl -Т обеспечивает проверку ошибок.
> Смотри также -------------------------------
Описание 4)ункций open и sysopen в perlfunc(1); рецепты 7.1, 7.7, 16.2,
19.4 и 19.6.
7.3. Тильды в именах файлов
Проблема
Имя файла начинается с тильды (например, -usemame/blah), однако функция open не интерпретирует его как обозначение домашнего каталога (home directory).Решение
Выполните ручное расширение с помощью следующей подстановки:$filename =- s{ ~ ~ ( ["/]* ) } { $1
? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR}
| (getpwuid($>))[7] ) }ех;
Комментарий
Нас интересуют следующие применения тильды:-user
-user/blah
-/blah
где user - имя пользователя. Если ~ не сопровождается никаким именем, используется домашний каталог текущего пользователя. В данной подстановке использован параметр /е, чтобы заменяющее выражение интерпретировалось как программный код Perl. Если за тильдой указано имя пользователя, оно сохраняется в $1 и используется getpwnam для выбора домашнего каталога пользователя из возвращаемого списка. Найденный каталог образует заменяющую строку. Если за тильдой не указано имя пользователя, подставляется либо текущее значение переменной окружения HOME или LOGDIR. Если эти переменные не определены, задается домашний каталог текущего пользователя.
> Смотри также
Описание функции getpwnam в perlfunc(1); man-страница getpwnam(2) вашей
системы; рецепт 9.6.
7.4. Имена файлов в сообщениях об ошибках
Проблема
Программа работает с файлами, однако в предупреждения и сообщения об ошибках Perl включается только последний использованный файловый манипулятор, а не имя файла.Решение
Воспользуйтесь именем файла вместо манипулятора:open($path, "< $path")
or die "Couldn't open $path for reading : $!\n";
Комментарий
Стандартное сообщение об ошибке выглядит так: Argument "3\n" isn't numeric in multiply at tallyweb line 16,> Смотри также -------------------------------
Описание функции open в perlfunc(1); рецепт 7.1.
7.5. Создание временных файлов
Проблема
Требуется создать временный файл и автоматически удалить его при завершении программы. Допустим, вы хотите записать временный конфигурационный файл, который будет передаваться запускаемой программе. Его имя должно быть известно заранее. В других ситуациях нужен временный файл для чтения и записи данных, причем его имя вас не интересует.Решение
Если имя файла не существенно, воспользуйтесь методом класса new_tmpfile модуля IO::File для получения файлового манипулятора, открытого для чтения и записи:use 10::File;
$fh = 10::File->new_tmpfile
or die "Unable to make new temporary file: $!"; Если имя файла должно быть известно, получите его функцией tmpnam из модуля POSIX и откройте файл самостоятельно:
use 10::File;
use POSIX qw(tmpnam);
# Пытаться получить временное имя файла до тех пор,
# пока не будет найдено несуществующее имя
do { $name = tmpnam() }
until $fh = 10::File->new($name, 0_ROWR|0_CREAT|0_EXCL);
# Установить обработчик, который удаляет временный файл tt при нормальном или аварийном завершении программы
END { unlink($name) or die "Couldn't unlink $name : $!" } # Перейти к использованию файла....
Комментарий
Если все, что вам нужно, - область для временного хранения данных, воспользуйтесь методом new_tmpfile модуля IO::File. Он возвращает файловый манипулятор для временного файла, открытого в режиме чтения/записи фрагментом следующего вида:for (;;) {
$name = tmpnam();
sysopen(TMP, $tmpnam, 0_RDWR | 0_CREAT | 0_EXC) && last;
} unlink $tmpnam; Файл автоматически удаляется при нормальном или аварийном завершении программы. Вам не удастся определить имя файла и передать другому процессу, потому что у него нет имени. В системах с поддержкой подобной семантики имя удаляется еще до завершения метода. Впрочем, открытый файловый манипулятор может наследоваться производными процессами'. Ниже показан пример практического применения new_tmpfile. Мы создаем временный файл, выполняем запись, возвращаемся к началу и выводим записанные данные:
use 10::File;
$fh = 10::File->new_tmpfile or die "10::File->new_tmpfile: $!";
$fh->autorlush(1);
print( $fh "$i\n" while $i++ < 10;
seek($fh, 0, 0);
print "Tmp file has: ", <$rh>; Во втором варианте создается временный файл, имя которого можно передать другому процессу. Мы вызываем функцию POSIX: :tmpnam, самостоятельно открываем файл и удаляем его после завершения работы. Перед открытием файла мы не проверяем, существует ли файл с таким именем, поскольку при этом может произойти подмена - кто-нибудь создаст файл между проверкой и созданием2. Вместо этого tmpnam вызывается в цикле, что гарантирует создание нового файла и предотвращает случайное удаление существующих файлов. Теоретически метод new_tmpfile не должен возвращать одинаковые имена разным процессам.
> Смотри также --------------------------------
Документация по стандартным модулям IO::File и POSIX; рецепт 7.19;
страница руководства tmpnam{3) вашей системы. Но перед вызовом ехес следует
присвоить УР хотя бы fileno($fh). 2 См. рецепт 19.4.
7.6. Хранение данных в тексте программы
Проблема
Некоторые данные должны распространяться вместе с программой и интерпретироваться как файл, но при этом они не должны находиться в отдельном файле.Решение
Лексемы __DATA__ и __END__ после исходного текста программы отмечают начало блока данных, который может быть прочитан программой или модулем через файловый манипулятор DATA. В модулях используется лексема __DATA__:while () { # Обработать строку }
„DATA__ и Данные
Аналогично используется __END__ в главном файле программы:
while (
# Обработать строку
}
-END__
# Данные
Комментарий
Лексемы __DATA__ и __END__ обозначают логическое завершение модуля или сценария перед физическим концом файла. Текст, находящийся после __ОАТА__ или __END__, может быть прочитан через файловый манипулятор DATA уровня пакета. Предположим, у нас имеется гипотетический модуль Primes; текст после __DATA__ в файле Primes.pm может быть прочитан через файловый манипулятор Primes::DATA. Лексема __END__ представляет собой синоним __DATA__ в главном пакете. Текст, следующий после лексем __END__ в модулях, недоступен. Появляется возможность отказаться от хранения данных в отдельном файле и перейти к построению автономных программ. Такая возможность нередко используется для документирования. Иногда в программах хранятся конфигурационные или старые тестовые данные, использованные при разработке программ, - они могут пригодиться в процессе отладки. Манипулятор DATA также применяется для определения размера или даты последней модификации текущей программы или модуля. В большинстве систем переменная $0 содержит полное имя файла для работающего сценария. В тех системах, где значение $0 оказывается неверным, можно воспользоваться манипулятором DATA для определения размера, даты модификации и т. д. Вставьте в конец файла специальную лексему __DATA__ (и предупреждение о том, что __DATA__ не следует удалять), и файловый манипулятор DATA будет связан с файлом сценария.use POSIX qw(strftime);
$raw_time = (stat(DATA))[9];
$size = -s DATA;
$kilosize = int($size / 1024) . 'k';
print "
Script size is $kilosize\n";
print strftime("
Last script update: %c (%Z)\n", localtime($raw_time));
__DATA__
DO NOT REMOVE THE PRECEDING LINE Everything else in this file will
be ignored.
> Смотри также ---------------------------
Раздел «Scalar Value Constructors» perldata(1).
|