2011-12-18 26 views
7

大容量ファイルの特定の行をメモリにロードせずに読み取る高速かつメモリ効率のよい方法はありますか?Perlの大容量ファイルから特定の行を読み取る

多くのフォークを実行するperlスクリプトを作成しました。ファイルから特定の行を読みたいと思います。外部コマンドを使用して瞬間イムで

sub getFileLine { 
    my ($filePath, $lineWanted) = @_; 
    $SIG{PIPE} = '_IGNORE_'; 
    open(my $fh, '-|:utf8', "tail -q -n +$lineWanted \"$filePath\" | head -n 1"); 
    my $line = <$fh>; 
    close $fh; 
    chomp($line); 
    return $line; 
} 

その高速とそれが動作する - など、高速で、この1のように効率的なメモリのような、より「のPerlっぽい」方法を、多分そこですか?

ご存じのように、Perlでフォークプロセスを作成すると、メインのプロセスメモリが複製されるため、メインプロセスで10MBが使用されている場合、フォークは少なくともその分を使用します。

私の目標はフォークプロセス(フォークを実行するまでのメインプロセスも)メモリをできるだけ使用しないようにすることです。それで私はなぜファイル全体をメモリにロードしたくないのですか?

+2

btw、それは '_IGNORE_'ではなく' IGNORE'です。 – ikegami

答えて

16

さらに進む前に、forkの仕組みを理解することが重要です。 forkプロセスでは、OSはcopy-on-writeセマンティクスを使用して、親プロセスと子プロセスの大部分のメモリを共有します。親と子の間で異なるメモリ量だけを別々に割り当てる必要があります。

open my $fh, '<', $filePath or die "$filePath: $!"; 
my $line; 
while(<$fh>) { 
    if($. == $lineWanted) { 
     $line = $_; 
     last; 
    } 
} 

これは、現在のファイルハンドルの行番号を保持している特殊な$.変数を使用しています:Perlでのファイルの単一の行を読み取るための

は、ここでは簡単な方法です。

4

コアモジュールTie::Fileをご覧ください。

+0

'Tie :: File'はメモリが不十分だと思っていました。 OPリクエストでメモリが不足していませんか? – Zaid

+0

@Zaidそれは実際に合理的にメモリ効率です。ファイルの内容全体をメモリに格納せず、各行の*オフセットのリストのみを格納します。それは自由ではありません(各オフセットに1行にいくらかのスペースを取るスカラーだけでも)。しかし、通常、数百メガバイトのファイルを簡単に処理するのに十分です。 – hobbs

+0

@hobbs:はい。それ以来、私はドキュメントを見てきました(コメントはかなり古くなっています)。そして、それはメモリ豚ではないことがはっきりしています。 – Zaid

0

フォークする必要はありません。あなたが想像することができるように、ファイルから特定の行を読み取ることは、CPAN上の20kモジュールの1つがすでにそれを行うのに十分な操作です。

File::ReadBackwardsは、メモリ効率が高く高速です。

関連する問題