【问题标题】:Monitoring and reading new lines in a file?监视和读取文件中的新行?
【发布时间】:2018-10-19 08:39:37
【问题描述】:

程序使用 AnyEvent 事件循环。程序应该读取有时(很少)出现在本地文件系统的文本文件中的新行。据我了解, AnyEvent::io 不能使用。我有什么建议从文件中读取新行?

【问题讨论】:

  • 嗯,请解释一下——你的意思是捕捉文件更改的事件并阅读对它所做的事情吗?或者是其他东西?并请展示(相关部分)“程序”。
  • 文件系统上有一个文本文件 (accept.txt),在启动时 perl 脚本会从中读取行并继续工作。有时可以将新行添加到文件中。添加这些行后,必须在程序中读取它们。
  • @Dmitriy 你可以试试AnyEvent::Inotify::Simple
  • 好的,这将是Linux::Inotify2 检测变化的工作;例如,参见this post。我可能会也可能不会在合理的时间范围内发布答案。您确实应该发布代码的相关部分。

标签: perl anyevent


【解决方案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 &amp;) 打印其行。然后添加到文件中

echo "new line\nanother" >> growing.txt

观察者打印出来

新队 其他

请参阅this post 了解更多信息和一些通用 cmets,并在您的系统上研究模块的文档和 man inotify

要执行此操作以及其他操作,您可以将其放在一个分叉的进程中,并在更改时将更改发送给父进程(通过pipesocketpair 或文件)。在处理过程中发生的任何事件仍然会被检测到,并在控件返回后作为新事件传递。

父母可以通过在循环中使用非阻塞IO::Select::can_read 或使用用户信号的信号处理程序(@987654335) 来处理何时 读取的问题@) 子在写入其管道结束后发送。

这是一个不太简单的东西的大纲。也有现成的解决方案。 AnyEvent 生态系统中的一些选项是 AnyEvent::Fork 和朋友 AnyEvent::Subprocess 及其“代表”机制 AnyEvent::Handle 以观察管道何时可以读取。

所有这些都需要一个事件循环,在这种情况下,所有工作都在处理程序(回调)中完成。然后主要工作可以在“空闲观察者”中完成,但这可能会有点令人费解,在这种特殊情况下,概述的用于子管理的手动方法最终可能会更加清晰。

监视器的最合适的管理取决于你的程序的细节。


如果文件以更改 inode 的方式更改,则上面的代码将无法检测到。许多常用工具都可能发生这种情况,例如 ziprsync 等。为了防止这种情况以及可能的文件消失,您可以使用其他标志来检测这些事件。

$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" }
});

对于 inode 更改,触发的是 IN_ATTRIB

然后您可能需要重新打开该文件(并且可能首先找到它)。一个单独的目录监视器在这里会很有帮助。所有这些也可以通过单独使用目录监视器来完成。

【讨论】:

  • @Dmitriy 进一步编辑,并对可能的监控环境发表评论
猜你喜欢
  • 1970-01-01
  • 2011-06-21
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 1970-01-01
  • 2013-08-18
  • 1970-01-01
相关资源
最近更新 更多