Как очистить файл в Perl? - PullRequest
22 голосов
/ 27 декабря 2010

У меня есть Perl-скрипт, который добавляет новую строку в существующий файл каждые 3 секунды.Кроме того, существует приложение C ++, которое читает из этого файла.

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

Ответы [ 9 ]

31 голосов
/ 27 декабря 2010

Попробуйте:

use IO::Handle;
$fh->autoflush;

Это было фактически объявлено как способ автоматической очистки в моем раннем вопросе , в котором был задан вопрос о общепринятом плохом способе достижения этого:-)

26 голосов
/ 19 июля 2013

TL / DR: используйте IO::Handle и метод flush, например:

use IO::Handle;
$myfile->flush();

Во-первых, вам нужно решить, насколько «промытым» он вам нужен.Может быть довольно много уровней буферизации:

  • Внутренний буфер Perl на дескрипторе файла.Другие программы не могут видеть данные, пока он не покинет этот буфер.

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

  • Буферизация записей с обратной записью на уровне диска.ОС считает, что они записаны на диск, но на самом деле диск просто хранит их в энергозависимой памяти на диске.В случае сбоя ОС данные не будут потеряны, но при сбое питания это может произойти, если только диск не сможет записать их первым.Это большая проблема с дешевыми потребительскими твердотельными накопителями.

Это становится еще сложнее, когда задействованы SAN, удаленные файловые системы, RAID-контроллеры и т. Д.Если вы пишете по каналам, есть еще и буфер канала.

Если вы просто хотите очистить буфер Perl, вы можете close файл, print строка, содержащая "\n" (так какпохоже, что Perl сбрасывает символы новой строки) или использует IO::Handle flush метод .

Вы также можете, за perl faq использовать binmode или поиграйте с $|, чтобы сделать дескриптор файла небуферизованным.Это не то же самое, что , как очистка буферизованного дескриптора, поскольку постановка в очередь группы буферизованных записей и выполнение одного сброса имеет гораздо меньшую производительность, чем запись в небуферизованный дескриптор.Если вы хотите очистить буфер обратной записи файловой системы, вам нужно использовать системный вызов, такой как fsync(), открыть файл в режиме O_DATASYNC или использовать одну из многочисленных других опций.Это мучительно сложно, о чем свидетельствует тот факт, что PostgreSQL имеет свой собственный инструмент для тестирования методов синхронизации файлов .

Если вы хотите убедиться, что он действительно, действительно, честен на жестком дискев постоянном хранилище вы должны сбросить его в файловую систему вашей программы.Вам также необходимо настроить жесткий диск / SSD / RAID-контроллер / SAN / что угодно, чтобы он действительно сбрасывался, когда операционная система запрашивает его.Это может быть удивительно сложно сделать, и это зависит от конкретной ОС / оборудования.Настоятельно рекомендуется провести пробное тестирование, чтобы убедиться, что вы правильно поняли.

15 голосов
/ 27 декабря 2010

Из 'man perlfaq5':

$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);

Если вы просто хотите сбросить стандартный вывод, вы можете просто сделать:это дает вам более удобную в использовании абстракцию, например IO::Handle.

2 голосов
/ 03 июля 2017

Вот ответ, реальный ответ.

STOP поддержание дескриптора открытого файла для этого файла на протяжении всего процесса.

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

#appends a new line to the existing file
sub append_new_line{
    my $linedata = shift;
    open my $fh, '>>', $fnm or die $!; # $fnm is file-lexical or something
    print $fh $linedata,"\n"; # flavor to taste
    close $fh;
}

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

2 голосов
/ 23 января 2013

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

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

Я пойман в ловушку с той же самой дилеммой, где у нас есть проблема с ротацией записываемого журнала.

1 голос
/ 27 декабря 2010

Чтобы автоматически очистить вывод, вы можете установить autoflush / $|, как описано другими , перед тем как выводить на дескриптор файла .

Если вы уже вывели на дескриптор файлачтобы убедиться, что он попадает в физический файл, вам нужно использовать методы IO :: Handle flush и sync.

1 голос
/ 27 декабря 2010

В PerlDoc есть статья об этом: Как очистить / снять буфер дескриптора выходного файла? Почему я должен это делать?

Два решения:

  • Отмените буферизацию обработчика выходных файлов с помощью: $|
  • Вызовите метод автозапуска, если вы используете IO::Handle или один из его подклассов.
0 голосов
/ 13 февраля 2013

Альтернативный подход заключается в использовании именованного канала между вашим Perl-скриптом и программой на C ++ вместо файла, который вы используете в данный момент.

0 голосов
/ 22 февраля 2012

У меня была та же проблема с той лишь разницей, что я снова и снова записывал один и тот же файл с новым контентом.Эта ассоциация "$ | = 1" и автозапуск работали для меня:

 open  (MYFILE, '>', '/internet/web-sites/trot/templates/xml_queries/test.xml');
 $| = 1; # Before writing!
 print  MYFILE "$thisCardReadingContentTemplate\n\n";
 close (MYFILE);
 MYFILE->autoflush(1); # After writing!

Удачи.H

...