Мониторинг и чтение новых строк в файле? - PullRequest
0 голосов
/ 09 сентября 2018

Программа использует цикл событий AnyEvent. Программа должна читать новые строки, которые иногда (редко) появляются в текстовом файле в локальной файловой системе. Как я понял, AnyEvent :: io использовать нельзя. Что я могу посоветовать читать новые строки из файла?

1 Ответ

0 голосов
/ 10 сентября 2018

Одним из способов является «просмотр» файла с помощью инструмента, который отслеживает и сообщает о событиях на объектах файловой системы.

Пример использования 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.

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

...