【发布时间】:2009-09-15 05:13:01
【问题描述】:
我从外部服务器获取数据流(文本格式),并希望将其逐行传递给脚本。该文件以连续方式附加。这是执行此操作的理想方法。使用 Perl 的 IO::Socket 方法可以吗?最终,这些数据必须通过 PHP 程序(可重复使用)并最终到达 MySQL 数据库。
问题是如何打开不断更新的文件?
【问题讨论】:
标签: perl
我从外部服务器获取数据流(文本格式),并希望将其逐行传递给脚本。该文件以连续方式附加。这是执行此操作的理想方法。使用 Perl 的 IO::Socket 方法可以吗?最终,这些数据必须通过 PHP 程序(可重复使用)并最终到达 MySQL 数据库。
问题是如何打开不断更新的文件?
【问题讨论】:
标签: perl
在 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
}
【讨论】:
$| 应该修改吗?
在 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;
}
【讨论】:
也许named pipe 会帮助你?
【讨论】:
你谈到打开一个文件,并询问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
}
您可能必须执行握手才能开始接收数据包,但这是另一回事。
【讨论】:
在 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
【讨论】:
阅读全文以寻求最后的解决方案是不明智的。如果在 Linux 下发生这种情况,我建议只重命名日志文件。然后,您可以扫描重命名文件中的所有实体,而原始文件中的实体将被重新填充。扫描所有重命名的文件后 - 删除它。或者移动到任何你喜欢的地方。这样你就可以得到类似 logrotate 的东西,但用于扫描新到达的数据。
【讨论】: