使用 Perl 分割大文本文件

2024-05-11

我必须将一个 1.8Tb 的大文本文件分成两部分(我只需要文件的后半部分)。该文件有\n作为记录分隔符。

I tried

perl -ne 'print if $. >= $line_to_start_from' test.txt > result.txt 

在一个小得多的 115Mb 测试文件上,它完成了工作,但花了 22 秒。

对 1.8Tb 文件使用此解决方案将花费不合理的长时间,所以我的问题是 Perl 中是否有一种方法可以分割大文件而不循环它们?


默认情况下,perl 一次读取一行文件输入。如果你的文件包含很多相对较短的行(我假设它确实如此),perl 将比像这样的实用程序慢很多split一次从文件中读取更大的块。

为了进行测试,我创建了一个约 200MB 的文件,其中包含很短的行:

$ perl -e 'print "123\n" for( 1 .. 50_000_000 );' >file_to_split

split可以相当合理地处理它:

$ time split --lines=25000000 file_to_split half

real    0m1.266s
user    0m0.314s
sys     0m0.213s

而简单的 Perl 方法要慢得多:

$ time perl -ne 'print if $. > 25_000_000' file_to_split >second_half

real    0m10.474s
user    0m10.257s
sys     0m0.222s

但您可以使用$/使 perl 一次读取多行的特殊变量。例如一次 16 kb 数据:

my $CHUNK_SIZE = 16 * 1024;
my $SPLIT_AT_LINE = 25_000_000;

{
    local $/ = \$CHUNK_SIZE;
    my $lineNumber = 0;
    while ( <> ) {
        if ( $lineNumber > $SPLIT_AT_LINE ) {
            # everything from here on is in the second half
            print $_;
        }
        else {
            my $count = $_ =~ tr/\n/\n/;
            $lineNumber += $count;
            if ( $lineNumber > $SPLIT_AT_LINE ) {
                # we went past the split, get some of the lines from this buffer
                my $extra = $lineNumber - $SPLIT_AT_LINE;
                my @lines = split m/\n/, $_, $count - $extra + 1;
                print $lines[ -1 ];
            }
        }
    }
}

如果您不关心超出几行的分割,则可以使此代码更加简单。这使得 perl 在合理的时间内完成相同的操作:

$ time perl test.pl file_to_split >second_half

real    0m0.678s
user    0m0.095s
sys     0m0.297s
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Perl 分割大文本文件 的相关文章

随机推荐