【问题标题】:Reading a specific line from large file in Perl从 Perl 中的大文件中读取特定行
【发布时间】:2012-01-22 23:44:04
【问题描述】:

是否有任何快速且内存效率高的方法来读取大文件的特定行,而无需将其加载到内存中?

我编写了一个 perl 脚本,它运行了许多分支,我希望它们从文件中读取特定的行。

目前我正在使用外部命令:

sub getFileLine {
    my ( $filePath, $lineWanted ) = @_;
    $SIG{PIPE} = '_IGNORE_';
    open( my $fh, '-|:utf8', "tail -q -n +$lineWanted \"$filePath\" | head -n 1" );
    my $line = <$fh>;
    close $fh;
    chomp( $line );
    return $line;
}

它速度快,而且有效——但也许还有一种更“Perl-ish”的方式,和这个一样快且内存效率高?

如您所知,在 Perl 中创建一个 fork 进程会复制主进程内存 - 所以如果主进程使用 10MB,fork 将至少使用那么多。

我的目标是保持 fork 进程(所以在运行 fork 之前的主进程)内存使用尽可能低。这就是为什么我不想将整个文件加载到内存中。

【问题讨论】:

  • 顺便说一句,这是IGNORE,而不是_IGNORE_

标签: perl file line


【解决方案1】:

在进一步了解之前,了解fork 的工作原理非常重要。当你fork一个进程时,操作系统使用copy-on-write语义来共享父进程和子进程的大部分内存;只有父子之间不同的内存量需要分开分配。

要在 Perl 中读取文件的单行,这里有一个简单的方法:

open my $fh, '<', $filePath or die "$filePath: $!";
my $line;
while( <$fh> ) {
    if( $. == $lineWanted ) { 
        $line = $_;
        last;
    }
}

这使用了特殊的$. 变量来保存当前文件句柄的行号。

【讨论】:

    【解决方案2】:

    看看Tie::File 核心模块。

    【讨论】:

    • 我认为Tie::File 内存效率低下。 OP 不是要求低内存使用吗?
    • @Zaid 它实际上是相当节省内存的;它不会将文件的全部内容存储在内存中,只有每行的 offsets 列表。它不是免费的(即使只是保存每个偏移量的标量也需要每行占用一些空间),但它通常足以轻松处理数百兆字节的文件。
    • @hobbs:是的。从那时起我就查看了文档(现在评论已经很老了),很明显它不是内存猪。
    【解决方案3】:

    你不需要分叉。可以想象,从文件中读取特定行是一项足够常见的操作,CPAN 上的 20k 模块中的一个已经做到了。

    File::ReadBackwards 内存效率高且速度快。

    【讨论】:

      猜你喜欢
      • 2014-07-25
      • 2014-07-29
      • 2014-10-13
      • 1970-01-01
      • 2013-08-03
      • 2011-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多