プロが教える店舗&オフィスのセキュリティ対策術

perl v5.10.0 built for i386-linux-thread-multi
OS: Fedora 9 (Linux localhost.localdomain 2.6.25.11-97.fc9.i686 #1 SMP Mon Jul 21 01:31:09 EDT 2008 i686 athlon i386 GNU/Linux)

巨大なテキストファイルの最終行を効率良く取得する方法を探しています。
検索を駆使して 6 日 6 晩試行錯誤したのですが、遂に見付けられなかった為、此所で質問させて頂きます。
私が知っている方法は以下の 3 つですが、何れも環境に依存するか、或いは効率が悪い等の理由で不完全です。

----------------
#!/usr/bin/perl

my $filename = './47GiB.txt';
my $file;

# 1.
print `tail -n 1 $filename`;

# 2.
open $file, $filename;
print +(<$file>)[- 1]; # print pop @{[<$file>]};
close $file;

# 3.
open $file, $filename;
my $pos = 0;
while (<$file>) {
$pos = tell $file unless eof $file;
}
seek $file, $pos, 0;
print <$file>;
close $file;
----------------

tail コマンドの様に、瞬時に最終行を読み出す方法は無いのでしょうか ?
御回答宜しくお願いします。

A 回答 (5件)

すみません, 「1回は読まないといけない」はウソです.


一度ファイルの最後までシークして, あとは
・適当な分だけ戻る
・read かなにかで読み込む
・改行があったら, そこからあとを「最後の行」とする
という感じでいけると思います. これだと実行時間はファイル全体の大きさに関係なく, 最後の行の長さにのみ依存するはずです. 最後の行に改行があるかないかまで考えるとちょっと嫌ですが.
    • good
    • 0
この回答へのお礼

以下の様なコードを書いて見ました。

----------------
use feature qw(:5.10);

my $filename = './47GiB.txt';
my $final;

open my $file, $filename or die "$filename: $!\n";

for (my $i = - 2;; $i --) {
last if eof $file;
seek $file, $i, 2;
my $line = <$file>;
next unless defined $line;
chomp $line;
last if $line eq '';
$final = $line;
}

say $final;
close $file;
----------------

最終行が空行の場合に $final は空文字列に成るべきかも知れませんが、一先ず実用上は問題無さそうです。
御回答有難う御座いました。

お礼日時:2008/08/08 20:52

File::Readbacwards


を使うってのは駄目なんだろうか.
seekして最後から探してくれるCPANモジュール.
PurePerlだし,必要な処理だけ移植するのも
難しくなさそう.
PerlHacksで紹介されてるくらいだから
きっと便利なものでしょう.
    • good
    • 0
この回答へのお礼

File::ReadBackwards を使う事にします。
御回答有難う御座いました。
大変貴重なモジュールを御紹介頂き、重ねて感謝申し上げます。

http://search.cpan.org/dist/File-ReadBackwards/R …
http://perldoc.jp/docs/modules/File-ReadBackward …

----------------
use File::ReadBackwards;
print File::ReadBackwards->new('./47GiB.txt')->readline;

お礼日時:2008/08/10 12:23

ファイルの最後から指定行数を取得


http://www.din.or.jp/~ohzaki/perl.htm#File_Tail

アルゴリズムとしてはANo.3と同じです。
    • good
    • 0
この回答へのお礼

非常に参考に成りました。
御回答有難う御座います。

お礼日時:2008/08/10 12:16

「最終行」を得るためには, どうしてもファイルを 1回は読む必要があります.


だったら素直に
open(my $fh, $filename);
my $lastline;
$lastline = $_ while <$fh>;
close $fh;
print $lastline;
でいいと思うんだけど, 気のせい?

この回答への補足

御回答有難う御座います。
御提示頂いたコードを見て居て閃きました。
続きます。

補足日時:2008/08/08 17:26
    • good
    • 0

こんなのありましたけど(参考URL参照)。


2. が単純な形で最も効率がいいように思いますけどなんかダメ
だったんでしょうか。

参考URL:http://tuka.s12.xrea.com/index.xcg?p=Perl#p5

この回答への補足

御回答誠に有難う御座います。
質問文の 3. のコードは、其のサイトのコードから着想を得て書いた物です。然し、速度が遅いです。
現在手元に件のテキストファイルが有るのですが、最終行を取得するのに可也の時間が掛かって仕舞って居ます。
より速いアルゴリズムはないのでしょうか ?

補足日時:2008/08/08 17:24
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!