Одним из способов является «просмотр» файла с помощью инструмента, который отслеживает и сообщает о событиях на объектах файловой системы.
Пример использования Linux :: Inotify2 , основанный на кратком изложении в документации модуля
use warnings;
use strict;
use feature 'say';
use AnyEvent;
use Linux::Inotify2;
my $file = shift @ARGV || 'growing.txt';
die "Usage: $0 file-to-watch\n" if not $file;
say '';
open my $fh, '<', $file or die "Can't open $file: $!";
print while <$fh>;
my $inotify = Linux::Inotify2->new or die "Can't create inotify object: $!";
$inotify->watch( $file, IN_MODIFY, sub {
my $e = shift;
if ($e->IN_MODIFY) {
print while <$fh>;
}
});
my $inotify_w = AnyEvent->io (
fh => $inotify->fileno, poll => 'r', cb => sub { $inotify->poll }
);
1 while $inotify->poll;
Монитор можно использовать со многими основными инструментами обработки событий. В этом примере используется AnyEvent .
Сначала создайте файл growing.txt
, предположительно, с некоторым содержимым. Затем запустите программу и поместите ее в фоновом режиме (watcher.pl &
), когда будут напечатаны ее строки. Затем добавьте в файл
echo "new line\nanother" >> growing.txt
и наблюдатель печатает
new line
another
Пожалуйста, смотрите в этом посте , чтобы узнать больше и некоторые общие комментарии, а также изучить документы по модулю и man inotify
в вашей системе.
Чтобы сделать это вместе с другими вещами, вы можете поместить его в раздвоенный процесс и отправить изменения родителю по мере их поступления (через pipe
, socketpair
или файлы). Любые события, происходящие во время обработки, по-прежнему обнаруживаются и доставляются как новые события после возврата элемента управления.
Родитель может иметь дело с вопросом , когда читать, выполняя свою другую работу в цикле с неблокирующим IO::Select::can_read
, или с обработчиком сигнала для пользовательского сигнала (SIGUSR1
) который ребенок отправляет после записи на конец трубы.
Это набросок чего-то не совсем простого. Есть и готовые решения. Некоторые опции из экосистемы AnyEvent
: AnyEvent :: Fork и друзья, AnyEvent :: Subprocess с его механизмом "делегатов", AnyEvent :: Handle для следите за этой трубкой, когда ее можно прочитать.
Все это также требует цикла обработки событий, и в этом случае вся работа выполняется в обработчиках (обратных вызовах). Тогда основная работа может быть выполнена, например, в режиме «ожидания», но это может оказаться немного запутанным, и в этом конкретном случае изложенный ручной подход к управлению детьми может оказаться более ясным.
Наиболее подходящее управление монитором зависит от деталей вашей программы.
Если файл изменяется таким образом, чтобы изменить индекс, приведенный выше код не сможет это обнаружить. Это может происходить со многими распространенными инструментами, такими как zip
, rsync
и т. Д. Чтобы обезопасить себя от этого, а также от возможного исчезновения файла, вы можете использовать другие флаги, чтобы обнаруживать эти события.
$inotify->watch( $file,
IN_MODIFY |IN_ATTRIB | IN_MOVE_SELF | IN_DELETE_SELF,
sub {
my $e = shift;
my $name = $e->fullname;
if ($e->IN_MODIFY) {
print while <$fh>;
}
if ($e->IN_ATTRIB) { say "$name meatadata changed" }
if ($e->IN_MOVE_SELF) { say "$name was moved" }
if ($e->IN_DELETE_SELF) { say "$name was deleted" }
});
Для изменения индекса запускается IN_ATTRIB
.
Тогда вам может понадобиться повторно открыть файл (и, возможно, сначала найти его). Отдельный монитор каталогов был бы очень полезен здесь. Все это также можно сделать с помощью одного только монитора каталогов.