【问题标题】:How do I read a file which is constantly updating?如何读取不断更新的文件?
【发布时间】:2009-09-15 05:13:01
【问题描述】:

我从外部服务器获取数据流(文本格式),并希望将其逐行传递给脚本。该文件以连续方式附加。这是执行此操作的理想方法。使用 Perl 的 IO::Socket 方法可以吗?最终,这些数据必须通过 PHP 程序(可重复使用)并最终到达 MySQL 数据库。

问题是如何打开不断更新的文件?

【问题讨论】:

标签: perl


【解决方案1】:

在 Perl 中,您可以使用 seek 和 tell 来读取不断增长的文件。它可能看起来像这样(从perldoc -f seek大量借用)

open(FH,'<',$the_file) || handle_error();  # typical open call
for (;;) {
    while (<FH>) {
        # ... process $_ and do something with it ...
    }
    # eof reached on FH, but wait a second and maybe there will be more output
    sleep 1;
    seek FH, 0, 1;      # this clears the eof flag on FH
}

【讨论】:

  • 对。 seek 和 tell 只是文件系统库函数。他们会用任何有它们的语言做同样的事情。
  • 会有缓冲问题吗? $| 应该修改吗?
【解决方案2】:

在 perl 中有几个模块可以更轻松地跟踪文件。 IO::Tail 和 File::Tail 一个使用回调,另一个使用阻塞读取,所以它只取决于哪个更适合您的需求。可能还有其他拖尾模块,但这是我想到的两个。

IO::Tail - 跟随文件/流的尾部

 use IO::Tail;
 my $tail = IO::Tail->new();
 $tail->add('test.log', \&callback);
 $tail->check();
 $tail->loop();

File::Tail - 用于从不断更新的文件中读取的 Perl 扩展

use File::Tail;
my $file = File::Tail->new("/some/log/file");
while (defined(my $line= $file->read)) {
    print $line;
}

【讨论】:

  • IO::Tail 的回调子中有什么?
【解决方案3】:

也许named pipe 会帮助你?

【讨论】:

  • 你能说得更具体点吗?
【解决方案4】:

你谈到打开一个文件,并询问IO::Socket。这些不是完全相同的东西,即使您在内心深处将要读取文件描述符的数据。

如果您可以从命名管道或 FIFO 访问远程流,那么您可以将其作为普通文件打开。当没有可用的数据时,它将阻塞,并在需要耗尽数据时返回。如果发件人跑得太远,您可能需要也可能不需要带File::Tail 来解决不丢失数据的问题。

另一方面,如果您直接打开一个套接字到另一台服务器(这似乎更有可能),IO::Socket 不会开箱即用,因为没有可用的getline 方法。您必须逐块读取和缓冲,然后通过中间握笔逐行分发。

您可以将套接字描述符提取到IO::Handle 中,并在其上使用getline()。比如:

my $sock = IO::Socket::INET->new(
    PeerAddr => '172.0.0.1',
    PeerPort => 1337,
    Proto    => 'tcp'
) or die $!;

my $io = new IO::Handle;
$io->fdopen(fileno($sock),"r") or die $!;

while (defined( my $data = $io->getline() )) {
    chomp $data;
    # do something
}

您可能必须执行握手才能开始接收数据包,但这是另一回事。

【讨论】:

    【解决方案5】:

    在 python 中它非常简单:

    f = open('teste.txt', 'r')
    for line in f: # read all lines already in the file
        print line.strip()
    
    # keep waiting forever for more lines.
    while True:
        line = f.readline() # just read more
        if line: # if you got something...
            print 'got data:', line.strip()
        time.sleep(1) # wait a second to not fry the CPU needlessy
    

    【讨论】:

    • 我猜你可能跑题了。请求者要求提供 Perl 示例。您发布了一个 python 示例。因此失败了。
    【解决方案6】:

    阅读全文以寻求最后的解决方案是不明智的。如果在 Linux 下发生这种情况,我建议只重命名日志文件。然后,您可以扫描重命名文件中的所有实体,而原始文件中的实体将被重新填充。扫描所有重命名的文件后 - 删除它。或者移动到任何你喜欢的地方。这样你就可以得到类似 logrotate 的东西,但用于扫描新到达的数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-19
      • 2010-10-29
      • 2014-09-30
      • 1970-01-01
      • 2021-02-14
      • 1970-01-01
      • 2020-10-28
      相关资源
      最近更新 更多