Perl дописать в файл

Обновлено: 07.07.2024

Открывается файл при помощи встроенной процедуры open . Процедура получает три параметра: переменную для создаваемого дескриптора, строку, обозначающую режим открытия (чтение, запись или что-то ещё), и, наконец, имя файла:

Мы обожаем совмещать объявление переменной для дескриптора с вызовом процедуры open :

Значение '<' , переданное как второй параметр, символизирует чтение. Знак «меньше», повернувшийся спиной к имени файла, как бы намекает нам, что готовится извлечение информации из файла. Угадайте, как открыть файл для записи? Конечно же так:

В примерах использования процедуры open указывалось относительное имя файла — по отношению к директории, являющейся для данной программы текущей. Сразу после запуска программы это та директория, из которой запущена программа. Но текущая директория может быть изменена процедурой chdir :

Нет никаких противопоказаний к тому, чтобы задавать при открытии абсолютное имя файла:

В некоторых операционных системах, в полных именах файлов применяется другой разделитель директорий. Например, в Microsoft DOS и Microsoft Windows вместо слэша / применяется разделитель бэкслэш \ . Тем не менее, задавая полное имя в программе на Perl при открытии, следует использовать слэш: '/c:/dos/autoexec.bat' .

Закрытие

Интуиция подсказывает нам, что всё, что открывается, должно быть рано или поздно закрыто. Это верно и для файлов. Любой сценарий ввода/вывода устроен одинаково: открытие, собственно ввод или вывод, и, наконец, закрытие.

Закрытие файла освобождает ресурсы операционной системы, занятые при открытии, и гарантирует, что данные, записанные в файл, дойдут по назначению. После закрытия переменная-дескриптор теряет актуальность и не может быть использована для ввода/вывода.

Для закрытия файлов служит встроенная процедура close :

Обработка ошибок при открытии и закрытии файлов

Не стоит ожидать, что открытие файла всегда будет успешным. Есть много причин, которые могут помешать. Среди них:

  • отсутствие нужного файла;
  • отсутствие прав на чтение или запись;
  • неполадки с носителем: испорченный диск или флешка, перебои с сетью в случае сетевых файлов.

Обратите внимание на специальную переменную $! . В случае возникновения ошибки в эту переменную автоматически помещается текст, объясняющий причину ошибки, например, Нет такого файла или каталога или Отказано в доступе или что-то ещё. Текст в $! , в зависимости от системных настроек, может быть на другом языке.

Гораздо изящней выглядит следующая идиома:

В этом логическом выражении два операнда. Если первый (то, что возвращает open ) принимает истинное значение, то в вычислении второго нет нужды, так как всё выражение уже заведомо истинно. Если же open возвратит ложное значение, то значение всего выражения определяется по второму операнду, который в этом случае должен быть вычислен. Для вычисления будет вызвана процедура die со всеми вытекающими последствиями.

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

Чтение

Имеется два способа чтения из дескриптора: побайтное/посимвольное и построчное.

Побайтное и посимвольное чтение

При побайтном/посимвольном чтении файла программа запрашивает у открытого дескриптора очередную порцию данных нужного размера и предоставляет скалярную переменную для запрошенных данных. Для чтения служит встроенная процедура read :

В этом примере предполагается, что $file — дескриптор файла, открытого для чтения, и что размер очередной запрошенной дозы информации — шестнадцать байт. Эти шестнадцать байт отправляются в переменную $buffer . После выполнения такой команды дескриптор выражает готовность читать дальше.

Можно представлять себе файл, открытый для чтения, как последовательность байтов. Воображаемый указатель отделяет уже прочитанную часть последовательности от ещё непрочитанной. Операция чтения приводит, помимо прочего, к сдвигу указателя к концу файла. За счёт этого следующая команда чтения получит доступ к новой порции данных. Дескриптор файла хранит в себе разнообразную информацию об открытом файле, и, в том числе, этот указатель — номер первого непрочитанного байта. Сразу после открытия указатель равен нулю.

Что же будет, если запросить при чтении больше байт, чем размер непрочитанной части файла? Ничего страшного, компьютер не сломается. Просто в переменную-буфер отправится меньше байт, чем было запрошено. Контролировать это явление удобно, пользуясь возвращаемым значением процедуры read — это количество байт, которое удалось прочесть. Широко распространена при программировании на Perl такая идиома:

Здесь значение, возвращённое из read , используется в качестве условия цикла. Рано или поздно файл будет прочитан до конца, и следующий вызов read возвратит ноль (ложное значение). Это прервёт цикл, что нам, собственно, и нужно.

Построчное чтение

В отличие от побайтного/посимвольного чтения, когда запрашивается заданное количество байтов или символов, при построчном чтении размер прочитанного заранее не оговаривается. Вместо этого считывается строка — последовательность байтов или символов вплоть до символа или символов, обозначающих конец строки.

Построчное чтение осуществляется оператором <…> . Код < $file > приводит к считыванию очередной строки из дескриптора $file в переменную по умолчанию $_ .

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

Здесь читатель справедливо задаётся вопросом: что именно печатает процедура print в теле цикла? Переменную по умолчанию, конечно. Можно было бы написать print $_ , но вряд ли это добавит ясности.

Другой пример. В уже открытом файле записаны числа, по одному в строке. Требуется вывести на экран их сумму.

Команда chomp необходима вот по какой причине. Оператор <…> вместе со строкой считывает и завершающий строку символ, который создаст проблему, если считанная строка впоследствии будет участвовать в арифметическом выражении. Встроенная процедура chomp удаляет этот символ, если строка заканчивается им. Если же последний символ другой, процедура ничего не делает. такая предосторожность нужна на тот случай, если, к несчастью, файл не заканчивается символом конца строки. Тогда и последняя прочитанная из файла строка закончится чем-то другим. Имеется также процедура chop , которая удаляет и возвращает последний символ строки независимо от того, какой он. Обе процедуры, chop и chomp , работают со строкой, переданной как параметр, но в отсутствие параметра — с переменной $_ .

Не следует думать, что с оператором построчного чтения мы обречены на использование переменной $_ . Если требуется читать в другую переменную, используем присваивание:

Самое время сообщить об одной особенности оператора построчного чтения. Его смысл немного меняется, если оператор поместить в списочный контекст, то есть туда, где должен быть список. Например, если присвоить массиву:

В этом случае все строки, прочитанный из файла, заполнят массив. Ещё можно организовать переборный цикл:

Этот код, как и приведённый выше цикл while , печатает строки файла на экран. К тому же результату приведёт код

(здесь пропущено слово for ). Но мы не рекомендуем такой подход, поскольку здесь сначала прочитываются все строки из файла, а затем передаются как список параметров в процедуру print . При этом все строки без всякой необходимости занимают память, а при большом файле объём памяти может быть очень велик.

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

Запись

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

Для записи в дескриптор применяется давно знакомая нам процедура print , но не совсем так, как мы привыкли:

Здесь содержимое строки $string записывается в открытый дескриптор $file . Обратите особое внимание на отсутствие запятой после первого параметра $file . С запятой смысл команды будет другим: в дескриптор ничего не запишется, а вместо этого программа выведет на экран строковое представление значений обеих переменных $file и $string :

(шестнадцатеричное число в скобках, скорее всего, будет другим, ну и вместо слова Привет! может оказаться другой текст). Число это нам ни о чём не говорит, как и загадочное слово GLOB вместе со скобками. Итак, если все параметры процедуры print разделены запятыми, все они печатаются на экран. Если после первого параметра нет запятой, этот параметр должен быть дескриптором, открытым для записи, а остальные параметры записываются в него:

Можно все параметры после дескриптора заключить в скобки:

Один из видных специалистов по языку Perl рекомендует заключать дескриптор в фигурные скобки, чтобы зрительно отделить его от остальных параметров:

Форматированный вывод

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

Таким способом можно вставлять в шаблон и строки, и числа. Что касается чисел, в каких-то ситуациях может потребоваться их особое форматирование. Числа перед включением в шаблон может потребоваться округлить до нужного количества десятичных цифр после точки, дополнить слева нужным количеством нулей или пробелов, чтобы число хорошо смотрелось в таблице. Может потребоваться вставить число в двоичном или шестнадцатеричном формате.

Теперь подробнее о форматных строках и форматных метках.

Если вставляемое число нужно вывести как целое (то есть с отбрасыванием дробной части), метка имеет вид %d :

Вот так можно выводить целые числа с выравниванием:

Для выравнивания числа можно дополнять слева не пробелами, а нулями:

Шестнадцатеричный формат с дополнением нулями до трёх цифр:

Двоичный формат с дополнением пробелами до четырёх знаков:

Округление с двумя цифрами после десятичной точки:

Приведённые примеры не охватывают все возможные форматы, понятные процедурам printf и sprintf , но для наших задач будет достаточно и этого.

Использование знака процента как признака метки лишает нас возможности использовать его в форматной строке как таковой. Эта трудность не новая для нас, и разрешается она уже хорошо знакомым способом. Комбинация из двух знаков процента означает одиночный знак процента (подобно тому, как \\ внутри "" -строк означает один бэкслэш):

Точно так же, как и print , процедура printf может осуществлять вывод не только на экран, но и дескриптор файла, открытого для записи или для добавления:

О том, что такое файл писать я надеюсь ненужно, но думаю нужно подумать над тем, что с ними можно делать, как видно из заголовка статьи, на Perl. Ну, приступим .

В этой статье обсудим:

Что такое файловые манипуляторы, и с чем их едят

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

Есть и стандартные Перловские файловые манипуляторы. Они называются STDIN (стандартный ввод), STDOUT (стандартный вывод) и STDERR (стандартный поток ошибок). Например параметры скрипту из формы передаются именно через STDIN (при условии использования метода POST).

Если понадобится создать копию файлового манипулятора (не файла, а только манипулятора по которому осуществляется доступ к файлу), то можно воспользоваться функцией open (о ней подробнее поговорим позже).

О присваивании переменным файловых манипуляторов:

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

Манипуляции с файлом

Открытие файла осуществляется функцией open.

Разберемся. У функции три параметра: FFF - название файлового манипулятора (его задаете вы), режим доступа ">" и "file.txt" - имя нужного вам файла. Есть три основных режима: ">" - запись,"<"- чтение, ">>"- добавление в файл.

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

В sysopen три обязательных параметра и один необязательный.

FH - собственно, файловый манипулятор, $name - имя файла в чистом виде (без ">" и др.). В $flags помещаем число, полученное объединением нижеописанных констант через OR ( | ):

O_RDONLY Только для чтения
O_WRONLY Только для записи
O_RDWR Для чтения и для записи
O_CREAT Если файла нет, создать!
O_APPEND Открытие в режиме присоединения
O_TRUNC Очищаем содержимое при открытии

Это, конечно, не полный перечень, но здесь перечислены самые необходимые и часто используемые константы.

И наконец $param. Этот параметр задает маску доступа к файлу и записывается в восьмеричной системе. Обычно используется значение 0666 (значение по умолчанию, то есть если $param опущен), или 0777. Первое значение используется для обычных файлов, второе же для каталогов и исполняемых файлов.

Пример открытия файла для записи (если не найден - создается):

Запись в файл делаем функцией print.

Здесь FFF - имя файлового манипулятора, а строка в кавычках - текст, который мы хотим записать в файл, ассоциированный с FFF.

Если до попытки открытия файла не существовало, то функция open его создаст, а если файл был, и он был не пустой, то после вышеуказанной функции print, в нем ничего не останется от предыдущей информации, а записана будет та ерунда, которую я там вписал.

Как уже было сказано, существуют три стандартных файловых манипулятора, и при опущенном файловом манипуляторе функция print осуществит вывод в STDOUT (то же относится к функциям printf и write). Чтобы изменить направление вывода в Perl предусмотрена функция select (правда не только для этого). Пример:

Закрываем файл функцией close.

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

Во-первых для чего? А для того, что если несколько процессов хотят одновременно заполучить доступ к файлу, причем на запись, причем еще и хотят туда что-то писать (кошмар), то представьте, что оказалось бы, если не этот чудный механизм блокировки. Он позволяет, грубо говоря, ставить процессы в очередь. Делаем так:

О функциях open и close уже говорили, а на flock остановимся немного подробнее. Она получает два параметра - файловый манипулятор и, образно говоря, категорию блокировки.

Про снятие блокировки: блокировка автоматически снимается при завершении процесса, вызванного текущим скриптом, либо при закрытии файлового манипулятора, который "привязан" к заблокированному файлу. Если вы снимаете блокировку вручную, будьте аккуратны - вы даете возможность другому процессу делать с (ВНИМАНИЕ!) не закрытым вами файлом все что ему угодно! Последствия могут быть, мягко говоря, неприятные, а грубо говоря - непредсказуемые (для вас непредсказуемые).

Работа со строками в файле

Так как именно те файлы, которые содержат строковую информацию составляют наибольший интерес для, собственно, человека, то и речь сейчас пойдет именно о них.

Для чтения строк из файла используется файловый манипулятор "поставленный" в <>.

Если не указано иначе, то внутри такого цикла используется стандартная переменная "$_", а номер строки записывается в "$.". Так как конец строки обозначается спецсимволом, например "\n", для получения самой строки (без эдакого "хвоста") нужно ее усечь функцией chomp.

Можно прочитать строки в массив:

Для передвижения по файлу используются функции tell и seek.

Функция tell принимает в качестве параметра файловый манипулятор, а seek берет три параметра. Первый - файловый манипулятор, второй - смещение в байтах, третий - направление смещение. Есть три направления смещения: 0 - от начала файла, 1 - от текущей позиции, 2 - с конца файла.

Нельзя сказать, что это все, что нам предлагает Perl для работы с файлами. Будем надеяться, что у меня будет время на то, чтобы написать о том, как работать с каталогами, тонкости при работе с бинарными файлами, объектно-ориентированный подход к управлению файлами и их содержимым.

Если вы пропустили предыдущие три части, я бы советовал начать чтение с начала . В принципе, эту серию уроков можно читать в произвольном порядке и во всем разобраться, но зачем усложнять себе жизнь?

В отличие от предыдущих уроков, которые можно было читать практически без подготовки, сегодня от вас потребуется понимание того, что такое стандартные потоки ввода и вывода, файловый дескриптор, права доступа к файлам и тп. К сожалению, эти вопросы выходят за рамки статьи, так что вам предстоит разобраться в них самостоятельно. К счастью, с этим вам поможет практически любая книжка по основам ОС семейства UNIX. Да и в сети соответствующих статей должно быть в изобилии.

Ввод и вывод

Как всегда, давайте начнем с примера:

Функция chomp проверяет, находится ли в конце строки-аргумента символ новой строки (\n) и если он присутствует, отсекает его. Если такого символа нет, строка остается без изменений.

print STDOUT "Вывод строки в стандартный поток вывода \n " ;
print STDERR "Вывод строки в стандартный поток ошибок \n " ;

Только что мы рассмотрели открытие файла на чтение. Чтобы открыть файл на запись, нужно перед его именем указать > или >>:

В заключение к этому разделу хотелось бы рассказать об интересной особенности оператора <>. Дело в том, что он может использоваться без указания файлового дескриптора:

В этом случае, если скрипт был вызван без аргументов, оператор будет производить чтение из STDIN. В противном случае все аргументы будут рассматриваться, как имена файлов. Чтение будет производиться по очереди из каждого файла. Можно сказать, что этот скрипт представляет собой аналог утилиты cat.

Работа с каталогами

Тут все настолько просто, что даже комментировать не хочется. Давайте лучше сразу перейдем к более интересному примеру:

Существует и более короткая запись:

А еще можно так:

Использовать функцию glob лучше в тех случаях, когда в выражение нужно подставить переменную.

Другие операции над файлами и каталогами

Также в Perl имеется несколько довольно полезных операторов:

Заключение

Дополнение. См также заметки, посвященные регулярным выражениям, объектно-ориентированному программированию в Perl и заливке модулей на CPAN. Можете считать их дополнениями к этой серии уроков.

Для нормальной работы в Perl с файлами и каталогами следует запомнить несколько важных процедур (см. таблицу).

Дескриптор представляет собой особый вид символьных переменных (literal string). Дескрипторы файлов, так же как и метки, применяются без специального префиксного символа, поэтому их можно спутать с существующими или зарезервированными словами (для подпрограмм, команд и пр.). При программировании названия дескрипторов рекомендуется писать только прописными буквами. Во-первых, они легко различимы среди остального текста, во-вторых, благодаря этому программа будет правильно выполняться. Дескриптор обычно представляет собой «название» файла, на который ссылается пользователь. Как и при программировании на Basic, Pascal или C/C++, дескрипторы в Perl подобны переменным, присутствующим в синтаксисе операций открытия, закрытия, считывания или записи в файл. Подобно другим языкам, Perl также использует дескрипторы в операциях манипулирования содержимым файлов. Однако есть и другие варианты их применения.

Существует три разных способа открытия файла для проведения чтения (read), дополнения (append) и записи (write).

Режим чтения (Read) — самый простой. Синтаксис операции open следующий:

Оператор open используется для открытия файла. В круглых скобках заключен дескриптор файла HANDLE. В дальнейшем при выполнении операций над файлом filename.txt и его содержимым на него будут приведены ссылки в программе. В кавычках стоит имя файла.

Для считывания информации из файла выполняется так называемая операция ромба, обозначаемая символами (<>):

Режим записи (Write) имеет следующий вид:

Отличие синтаксиса операций записи от синтаксиса чтения заключается лишь в том, что перед именем файла стоит символ «больше чем» (>). Этот знак сообщает, что следует создать указанный в кавычках файл и записать или обновить (если он уже существует) его содержимое. Чтобы записать в него информацию, нужно обратиться к помощи оператора print:

Режим добавления (Append) синтаксически выглядит так:

Он схож с режимом записи. Разница лишь в том, что при его описании ставится двойной знак «больше чем» (>>). Если указанный файл не существует, то он будет создан, в противном случае введенная информация будет добавлена в конец. Когда выполняется операция дополнения, данные можно не только записывать, но и считывать из файла.

В случае успешного выполнения все формы функции open возвращают значение true, а в случае неудачи — false. Например, если при попытке открыть файл для чтения выдается значение false, то это означает, что файла нет или доступ к нему запрещен. А когда при открытии файла для ввода информации это значение возвращается, то можно сделать вывод, что либо файл защищен от записи, либо невозможна запись в каталог или доступ к нему. Если затем программа завершит свою работу или файл заново откроется, то не нужно закрывать его после окончания работы с дескриптором — операция открытия файла закрывает ранее задействованный дескриптор. Тем не менее лучше все же закрыть файл с помощью операции close. Подобная структура является «хорошим тоном» при программировании:

В синтаксисе совмещения open и die используется «логическое ИЛИ» (||):

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

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

Есть множество других операций для проверки файлов. Например, чтобы убедиться в наличии какого-либо файла и возможности чтения из него, нужно вместо операции -e выполнить -r, а в случае требования возможности записи —w. Можно проверить один и тот же файл на доступность чтения и записи информации, выполнив следующее:

Чтобы определить возможность чтения для целой группы файлов с одинаковым расширением, можно использовать конструкцию:

При большинстве подобных проверок, а их около 20, возвращается значение true или false.

Отличия от Win32. При работе на Perl под управлением Windows существуют некоторые нюансы, о которых следует знать. Во-первых, нужно указывать полный путь к файлу (вместе с именем диска), над которым будут выполняться какие-либо действия, например

Во-вторых, блокировка файла происходит иначе, чем в Unix-системах. При использовании Windows 9.x эта операция вообще не поддерживается, а в Windows NT выполняется весьма своеобразно — перед выполнением команд копирования или изменения имени файла нужно удостовериться, что вы уже закрыли его. Иначе они просто не выполнятся.

Для записи в файл он открывается в режиме записи, как показано ниже:

Если файл существует, он усекает старое содержимое файла с новым содержимым. В противном случае будет создан новый файл и добавлено содержимое.

функция print ()

Функция print () используется для записи содержимого в файл.

Syntax: print filehandle string

Здесь дескриптор файла связан с файлом во время открытия файла, а строка содержит содержимое, которое должно быть записано в файл.

Пример :

open (fh, ">" , "Hello.txt" );

print "Enter the content to be added\n" ;

close (fh) or "Couldn't close the file" ;


Перед записью в файл:


Выполнение кода для записи:


Обновленный файл:

Вот как работает программа:
Шаг 1: Открытие файла Hello.txt в режиме записи.
Шаг 2: Получение текста со стандартной клавиатуры ввода.
Шаг 3: Запись строки, хранящейся в $ a, в файл, указанный в дескрипторе файла fh
Шаг 4: Закрытие файла.

Копирование содержимого из одного файла в другой:

Перед выполнением кода:
Исходный файл:

Файл назначения:

Пример :
Пример ниже считывает содержимое из исходного файла и записывает его в конечный файл.

print ( "Copying content from $src to $des\n" );

print "File content copied successfully!\n" ;


Выполнение кода:


Обновленный файл назначения:

Вот как работает программа:
Шаг 1: Открытие 2 файлов Source.txt в режиме чтения и Destination.txt в режиме записи.
Шаг 2: Чтение содержимого из FHR, который является файловым дескриптором для чтения содержимого, в то время как FHW является файловым дескриптором для записи содержимого в файл.
Шаг 3: Копирование содержимого с использованием функции печати.
Шаг 4: Закройте conn, как только чтение файла будет завершено.

Обработка ошибок и отчеты об ошибках

Есть два способа обработки ошибок

  • Создайте исключение, если файл не может быть открыт (Обработка ошибки)
  • Выдать предупреждение, если файл не может быть открыт и продолжен (Отчет об ошибках)

open (fh, '<' , $filename ) or

die "Couldn't Open file $filename" ;


В приведенном выше коде, когда File существует, он просто выполняется без ошибок, но если файл не существует, он генерирует ошибку и код завершается.

if ( open (fh, '<' , $filename ))

warn "Couldn't Open a file $filename" ;


Когда файл существует:


Когда Файл не существует:

Читайте также: