печать Perl в файл и STDOUT, который является файлом - PullRequest
0 голосов
/ 24 мая 2019

Моя программа пытается распечатать файл, который для него является STDOUT.Например, print "text here"; печатает в файл x.log, в то время как я также пытаюсь печатать в файл x.log, используя метод-обработчик файла, как в print FH1 "textздесь "; .Я заметил, что когда сначала предоставляется оператор метода file-handler, а затем процедура STDOUT.Мой второй отпечаток может переопределить первый. Я хотел бы узнать больше о том, почему это происходит.

Это заставляет меня думать о состоянии гонки или о том, что обработчик файлов является относительно медленным (если он проходит через буфер?), Чем операторы печати STDOUT.В этом я не уверен, как это работает на Perl.Версия Perl - 5.22.0

1 Ответ

4 голосов
/ 24 мая 2019

Насколько я понимаю, ваша программа в основном выглядит следующим образом:

open(my $fh,'>','foobar.txt');
print $fh "foo\n";
print "bar\n"; # prints to STDOUT

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

$ perl test.pl > foobar.txt

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

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

В дополнение к этому также выполняется внутренняя буферизация, т. Е. Каждая print сначала приводит к записи в некоторый внутренний буфер и может немедленно привести к записи вдескриптор файла.Когда данные записываются в дескриптор файла, зависит от режима дескриптора файла, то есть небуферизованного, строкового буфера или буфера определенного размера.Это делает результат вроде непредсказуемым.

Если вы не хотите такого поведения, но по-прежнему хотите записывать в один и тот же файл, используя несколько файловых дескрипторов, вам лучше использовать режим добавления, то есть открывать с >> вместо > в обоих кодах Perlи оболочка.Это гарантирует, что все данные будут добавлены в конец файла, а не записаны в положение файла, поддерживаемое дескриптором файла.Таким образом, данные не будут перезаписаны.Кроме того, вы можете захотеть сделать дескрипторы файлов небуферизованными, чтобы данные в файле были в том же порядке, что и операторы print, где это сделано:

open(my $fh,'>>','foobar.txt');
$fh->autoflush(1); # make $fh unbuffered
$|=1;   # make STDOUT unbuffered
print $fh "foo\n";
print "bar\n"; # prints to STDOUT

$ perl test.pl >> foobar.txt
...