在Perl中读写文件的特定行,最佳方法是什么?

3
我是一名有用的助手,可以为您翻译文本。
我正在尝试读取文件的最后一行。 有许多可用于读取特定文件行的方法。
第一种方法:
  @array=<FILE_HANDLE>;
    $line=(reverse @array)[0];

第二:ReadBackwards包
$bw = File::ReadBackwards->new( 'log_file' ) or
                        die "can't read 'log_file' $!" ;
 $log_line = $bw->readline;

我想知道在Perl中,哪种方法更可取,是使用包还是将整个文件内容存储到变量中。

1
你如何定义“最好”?是最快的、最节省内存的、或者在下一个人看来最容易阅读的? - simbabque
2个回答

4
你的标题和正文提出了不同的问题。
要读取任意大文件中的最后一行(或倒数第n行),绝对可以使用File::ReadBackwards。
要在文件中读取或写入任意单行,请使用Tie::File:
use Tie::File;
tie my @line, 'Tie::File', 'filename' or die "unable to open filename: $!";
print "line 123 is $line[123].";
$line[42] = 'abc';
print "line 42 is now abc.";

对于大文件而言,这种方法的代价要高于 File::ReadBackwards,因为它需要读取整个文件直到您想修改的那一行(或者如果使用负索引,则需要读取整个文件。因此,如果您这样做了,最好还是使用 File::ReadBackwards 然后手动更新文件)。


作为比较,这个是你的Tie::File片段的高效替代方案。它使用的内存要少得多,并且速度更快。 - ikegami
@ikegami: 你有“更少内存”的数字吗? - ysth
1
忽略可配置大小的行缓存,T::F 在内存中保留遇到的每一行的索引。在您的示例中,这将是文件的每一行。如果我没记错,在我使用的机器上,每行大约是 64 字节。对于您典型的 Perl 程序文件,使用 T::F 读取文件实际上比将整个文件存储在一个标量中使用更多的内存! - ikegami
@ikegami:那应该就是一个答案了! - Fabio says Reinstate Monica
@Fabio Turati,您是指链接的代码吗?它专门用于小的负偏移量。ysth的Tie::File片段当时使用的是$line[-10]而不是$line[42]。这远远不是一个完整的答案。 - ikegami
显示剩余4条评论

-2
问题在于 - 没有一种方法不依赖于读取整个文件。文件从开头开始,您的进程必须全部查找。 这是代码执行的最昂贵任务,因此采用哪种方法几乎没有什么区别。
所以我会选择一个非常简单的方法:
 my $last_line; 
 while ( my $line = <$filehandle> ) { $last_line = $line }; 
 print $last_line,"\n";

这看起来可能效率不高,但它所做的事情与其他操作一样 - 读取整个文件,并且丢弃除最后一行以外的所有内容。

如果 - 如您的问题所示 - 您想要一个 - 特定的 - 行 - 您可以使用测试 $.(当前行号)或正则表达式,并在满足条件时“退出”循环。因此,您不需要读取整个文件,这会略微提高效率。

E.g.:

while ( my $line = <$filehandle> ) { 
    $last_line = $line;
    last if $. >= 100; #bails out after we hit line 100. 
    last if m/END FILE/; #looks for 'END FILE' on the line, and bails out. 
}; 
print $last_line,"\n";

你可以从文件末尾以块的形式读取文件,搜索换行符。这样你就不需要读取整个文件。 - rustyx
1
@rustyx 是的,这就是 File::ReadBackwards 为您所做的。 - ysth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接