ほとんどの場合、ファイル全体を一度に読み込む必要はありません。readline 演算子は、スカラー コンテキストで呼び出された場合、一度に 1 行だけを返します。
1 while <INPUT>; # read a line, and discard it.
say "The line count is = $.";
$.
特殊変数は、最後に読み取られたファイルハンドルの行番号です。
編集:行数は単なる例です
Perl は大きな配列に問題はありません。システムに十分なメモリがないようです。Perl 配列は C 配列よりも多くのメモリを使用することに注意してください。これは、スカラーがフラグなどに追加のメモリを割り当てるためであり、配列は段階的に増加するためです。
メモリが問題になる場合は、ファイル全体をメモリにロードする必要があるアルゴリズムから、一度に 1 行だけ保持するアルゴリズムに変換する必要があります。
例: 数ギガバイトのファイルのソート。ここでは、通常のアプローチprint sort <$file>
は機能しません。代わりに、ファイルの一部を並べ替えて一時ファイルに書き込み、巧妙な方法で一時ファイルを切り替えて、1 つの並べ替えられた出力を生成します。
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
。
この一般的なアプローチは、あらゆる種類の問題に適用できます。これは「分割統治」戦略です。問題が大きすぎる場合は、小さな問題を解決してから、断片を結合します。