perl - 跳过文件的前 x 行和最后 y 行

标签 perl

我正在对文本文件(可能达到 1GB 范围)进行一些简单的解析。我将如何跳过前 N 行,更重要的是,跳过最后(不同的)N 行?我确信我可以打开文件并计算行数,然后用 $_ < total_row_count -N 做一些事情,但这似乎非常低效。 顺便说一句,我几乎是 perl 新手。

最佳答案

文件是一个字节序列,没有“行”的概念。其中一些字节被视为“行”分隔符(换行符),这就是软件为我们提供“逻辑”行的方式。因此,没有办法知道文件中有多少行 - 没有读取并计算它们。

一种简单而幼稚的方法是逐行阅读并计数

open my $fh, '<', $file  or die "Can't open $file: $!";

my $cnt;
++$cnt while <$fh>;

使用 $. variable 的更快版本

1 while <$fh>;
my $cnt = $.;

在一个合理的桌面上,一个 1.1 Gb 的文本文件需要 2.5 到 3 秒。

我们可以通过读取更大的 block 并计算换行符来加快速度

open my $fh, '<', $file  or die "Can't open $file: $!";

my $cnt; 
NUM_LINES: {
    my $len = 64_000; 
    my $buf;

    $cnt += $buf =~ tr/\n// 
        while read $fh, $buf, $len;

    seek $fh, 0, 0;
};

在相同的硬件和 Perl 版本上,这仅用了半秒多一点。

我已经将它放在一个 block 中以限定不需要的变量,但它应该在一个子中,然后您可以在其中检查文件句柄的位置,然后在计数后将其返回那里(这样我们就可以计算“其余” 文件中某个点的行,然后处理可以继续)等。它还应该包括在每次调用时对 read 操作的检查。

我认为 Gb 大文件的半秒开销一点也不坏。

不过,您可以更快地进行,但代价是变得更加困惑。获取文件大小(元数据,因此不涉及读取)和 seek 到估计为结束前所需行数的位置(不涉及读取)。那很可能不会到达正确的位置,因此请阅读到最后以计算行数并进行调整,然后再寻找(更远或更近)。重复直到你到达需要的地方。

open my $fh, "<", $file; 
my $size = -s $file;

my $estimated_line_len = 80;
my $num_last_lines     = 100;

my $pos = $size - $num_last_lines*$estimated_line_len;

seek $fh, $pos, 0; 

my $cnt;    
++$cnt while <$fh>; 

say "There are $cnt lines from position $pos to the end"; 

# likely need to seek back further/closer ...

我猜这应该让您在 100 毫秒内到达那里。请注意,$pos 可能在一行内。

然后,一旦您知道行数(或结束前所需行数的位置),请执行 seek $fh, 0, 0 并处理。或者真的把它放在一个 sub 中,它把文件句柄放回返回之前的位置,如前所述。

关于perl - 跳过文件的前 x 行和最后 y 行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58441214/

相关文章:

perl - 如何获取可在\N{} 中使用以生成特定代码点的所有值?

database - 如何将 Perl 数据序列化和反序列化到数据库或从数据库反序列化?

perl - Perl中的&function和function()之间的区别

perl - 高级 perl 语法 - Mojo::DOM

Perl <STDIN> 不匹配数组中的内容

linux - 为什么这个egrep命令在我的shell中有效,但在Perl中无效?

perl - 在函数调用的同一行获取散列键/值

perl - 如何通过多个键对 perl 哈希进行排序?

perl - 如何让一个 Perl 脚本查看另一个 Perl 脚本中的变量?

perl - 哈希值中的 4/16 是什么?