我需要将一个1.8Tb的大型文本文件分为两个文件(我只需要文件的后半部分)。这个文件的记录分隔符是\n
。
我尝试过:
perl -ne 'print if $. >= $line_to_start_from' test.txt > result.txt
我使用这个解决方案在一个大小为115Mb的小测试文件上可以完成工作,但需要22秒的时间。
对于一个1.8Tb的大文件使用这个解决方案将需要不合理长的时间,所以我的问题是是否有一种在Perl中分割巨大文件而不需要循环的方法?
我需要将一个1.8Tb的大型文本文件分为两个文件(我只需要文件的后半部分)。这个文件的记录分隔符是\n
。
我尝试过:
perl -ne 'print if $. >= $line_to_start_from' test.txt > result.txt
我使用这个解决方案在一个大小为115Mb的小测试文件上可以完成工作,但需要22秒的时间。
对于一个1.8Tb的大文件使用这个解决方案将需要不合理长的时间,所以我的问题是是否有一种在Perl中分割巨大文件而不需要循环的方法?
默认情况下,Perl 逐行读取文件输入。如果您的文件包含大量相对较短的行(我假设是这种情况),那么与像 split
这样从文件一次性读取更大块内容的实用程序相比,Perl 将慢得多。
为了进行测试,我创建了一个非常短的行的 ~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
tail
呢? - chorobaperl -we'$f=shift//die"need filename\n"; open $fh, $f; while (<$fh>) { last if $.>=10 }; print <$fh>' text.txt > result.txt
(将“10”替换为所需的行号)?引用的22秒太长了。在一个123Mb的文件中,该单行程序花费了1.15秒,并提取200万行后的所有内容(大约一半 - 输出为62Mb)。这是在一个7-8年的老笔记本电脑上使用perl 5.16完成的。 - zdim