• ベストアンサー

巨大なテキストの最終行を取得するには

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

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

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

_--_--_-_-
質問者

お礼

以下の様なコードを書いて見ました。 ---------------- 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 は空文字列に成るべきかも知れませんが、一先ず実用上は問題無さそうです。 御回答有難う御座いました。

その他の回答 (4)

  • kabaokaba
  • ベストアンサー率51% (724/1416)
回答No.5

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

_--_--_-_-
質問者

お礼

File::ReadBackwards を使う事にします。 御回答有難う御座いました。 大変貴重なモジュールを御紹介頂き、重ねて感謝申し上げます。 http://search.cpan.org/dist/File-ReadBackwards/ReadBackwards.pm http://perldoc.jp/docs/modules/File-ReadBackwards-1.02/ReadBackwards.pod ---------------- use File::ReadBackwards; print File::ReadBackwards->new('./47GiB.txt')->readline;

回答No.4

ファイルの最後から指定行数を取得 http://www.din.or.jp/~ohzaki/perl.htm#File_Tail アルゴリズムとしてはANo.3と同じです。

_--_--_-_-
質問者

お礼

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

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

「最終行」を得るためには, どうしてもファイルを 1回は読む必要があります. だったら素直に open(my $fh, $filename); my $lastline; $lastline = $_ while <$fh>; close $fh; print $lastline; でいいと思うんだけど, 気のせい?

_--_--_-_-
質問者

補足

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

  • pick52
  • ベストアンサー率35% (166/466)
回答No.1

こんなのありましたけど(参考URL参照)。 2. が単純な形で最も効率がいいように思いますけどなんかダメ だったんでしょうか。

参考URL:
http://tuka.s12.xrea.com/index.xcg?p=Perl#p5
_--_--_-_-
質問者

補足

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

関連するQ&A