Мониторинг и чтение новых строк в файле?
Программа использует цикл событий AnyEvent. Программа должна читать новые строки, которые иногда (редко) появляются в текстовом файле в локальной файловой системе. Как я понял, AnyEvent::io использовать нельзя. Что я могу посоветовать для чтения новых строк из файла?
1 ответ
Одним из способов является "просмотр" файла с помощью инструмента, который отслеживает и сообщает о событиях на объектах файловой системы.
Пример использования 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
и наблюдатель печатает
новая линия другой
Пожалуйста, посмотрите этот пост, чтобы узнать больше и некоторые общие комментарии, а также изучить документы и man inotify
в вашей системе.
Чтобы сделать это вместе с другими вещами, вы можете поместить его в раздвоенный процесс и отправить изменения родителю по мере их поступления (через pipe
, socketpair
или файлы). Любые события, которые происходят во время обработки, по-прежнему обнаруживаются и доставляются как новые события после возврата элемента управления.
Родитель может решать вопрос о том, когда читать, выполняя свою другую работу в цикле с неблокирующим IO::Select::can_read
или с обработчиком сигнала для пользовательского сигнала (SIGUSR1
) который ребенок отправляет после записи в конец трубы.
Это набросок чего-то не совсем простого. Есть и готовые решения. Некоторые варианты из AnyEvent
экосистемой являются AnyEvent:: Fork и друзья, https://metacpan.org/pod/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
это уволено.
Затем вам может понадобиться повторно открыть файл (и, возможно, сначала найти его). Отдельный монитор каталогов был бы очень полезен здесь. Все это также можно сделать с помощью одного только монитора каталогов.