2011-12-18 105 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; 
} 

其快速和它的作品 - 但也許有更多的「Perl的十歲上下」的方式,以最快的速度和內存效率,因爲這一個?

正如你所知,在Perl中創建一個fork進程會重複主進程內存 - 所以如果主進程使用10MB,fork至少會使用那麼多。

我的目標是保持叉過程(所以主流程,直到運行叉也)內存使用盡可能低。這就是爲什麼我不想將整個文件加載到內存中。

+2

btw,它是'IGNORE',而不是'_IGNORE_'。 – ikegami

回答

16

在您走得更遠之前,瞭解fork的工作原理非常重要。當你使用fork進程時,操作系統使用copy-on-write語義來共享父進程和子進程的大部分內存;只有父母和孩子之間不同的內存數量需要分開分配。

用於讀取的Perl文件的單行線,這裏有一個簡單的方法:

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

本品採用特殊$.變量,保存當前的文件句柄的行號。

4

看看Tie::File核心模塊。

+0

我以爲'Tie :: File'是內存效率低下的。 OP沒有請求低內存使用率嗎? – Zaid

+0

@Zid它實際上是合理的內存效率;它不會將文件的全部內容存儲在內存中,而只是每行的*偏移*列表。它不是免費的(即使只是每個偏移量的標量都佔用一行空間),但它通常足以處理數百兆字節的文件。 – hobbs

+0

@hobbs:是的。從那時起我已經看過文檔(現在評論已經很老了),並且非常清楚,它不是一個記憶豬。 – Zaid

0

你不需要分叉。正如你可以想象的,從文件中讀取特定的行是一種常見的操作,CPAN上的20k模塊中的一個已經可以完成它了。

File::ReadBackwards內存效率高,速度快。