大多数情况下,您不需要一次读取整个文件。在标量上下文中调用时,readline 运算符一次只返回一行:
1 while <INPUT>; # read a line, and discard it.
say "The line count is = $.";
$.
特殊变量是最后读取的文件句柄的行号。
编辑:行数只是一个例子
Perl 对大型数组没有问题,只是您的系统似乎没有足够的内存。请注意,Perl 数组比 C 数组使用更多内存,因为标量会为标志等分配额外的内存,并且因为数组会以递增的步长增长。
如果内存是一个问题,您必须将您的算法从必须将整个文件加载到内存中的算法转换为一次只保留一行的算法。
示例:对数 GB 的文件进行排序。正常的方法print sort <$file>
在这里行不通。相反,我们对文件的某些部分进行排序,将它们写入临时文件,然后以一种巧妙的方式在临时文件之间切换以产生一个排序的输出:
use strict; use warnings; use autodie;
my $blocksize = shift @ARGV; # take lines per tempfile as command line arg
mkdir "/tmp/$$"; # $$ is the process ID variable
my $tempcounter = 0;
my @buffer;
my $save_buffer = sub {
$tempcounter++;
open my $tempfile, ">", "/tmp/$$/$tempcounter";
print $tempfile sort @buffer;
@buffer = ();
};
while (<>) {
push @buffer, $_;
$save_buffer->() if $. % $blocksize == 0;
}
$save_buffer->();
# open all files, read 1st line
my @head =
grep { defined $_->[0] }
map { open my $fh, "<", $_; [scalar(<$fh>), $fh] }
glob "/tmp/$$/*";
# sort the line-file pairs, pick least
while((my $least, @head) = sort { $a->[0] cmp $b->[0] } @head){
my ($line, $fh) = @$least; print $line;
# read next line
if (defined($line = <$fh>)){
push @head, [$line, $fh];
}
}
# clean up afterwards
END {
unlink $_ for glob "/tmp/$$/*";
rmdir "/tmp/$$";
}
可以称为$ ./sort-large-file 10000 multi-gig-file.txt >sorted.txt
.
这种通用方法可以应用于各种问题。这是一种“分而治之”的策略:如果问题太大,解决一个较小的问题,然后将各个部分组合起来。