たつをの ChangeLog : 2010-08-10

テキストファイルから指定した行を取り出すタスクについて。

頭から走査する方法


まずはファイルの頭から走査していくナイーブな方法。

■コード(getline-naive.pl):
#!/usr/bin/perl
use strict;
use warnings;
my $qidx = shift @ARGV; # start from 0
my $tgtfn = shift @ARGV;
open(my $fh, "<", $tgtfn) or die;
while (<$fh>) {
    next if $. != $qidx + 1;
    print;
    last;
}
close $fh;

先頭行は0行目になる仕様。

■実行例:
% cat test.dic
Japan
Tokyo
Yokohama
This is a pen
Hello World
% ./getline-naive.pl 2 test.dic
Yokohama

インデックスを使う方法


頭から走査する方法はファイルサイズが巨大になると破綻するのでインデックスを使う。
まずインデックスを作成するプログラム。

■コード(mkidx.pl):
#!/usr/bin/perl
use strict;
use warnings;
my $ip = 0;
while (<>) {
    print pack("N", $ip);
    $ip += length($_);
}

■実行例:
% ./mkidx.pl test.dic > test.dic.ary
% od -t x1 test.dic.ary
0000000  00 00 00 00 00 00 00 06 00 00 00 0c 00 00 00 15
0000020  00 00 00 23
0000024

各行の先頭バイト位置を固定長バイトにして出力。
SUFARY の "mkary -l -ns" と同じ出力になる。
というか、互換にしてみた。

N行目(0始まり)の開始バイト位置は「N * sizeof(unsigned long)」個目に格納されている。
なので、あとは seek と read で行を取り出せばOK。
ゆえに頭から見ていく前述の方法よりも高速になる。

ということで、インデックスを使った指定行取り出しプログラム。

■コード(getline.pl):
#!/usr/bin/perl
use strict;
use warnings;

my $len_of_N = 4;

my $qidx = shift @ARGV;	# start from 0
my $tgtfn = shift @ARGV;
my $idxfn = shift @ARGV || $tgtfn.".ary";

my $tfsz = -s $tgtfn;
my $ifsz = -s $idxfn;
die if $qidx < 0 or $qidx * $len_of_N >= $ifsz;

my $buf = "";

open(my $fi, "<", $idxfn) or die;
seek $fi, $qidx * $len_of_N, 0;
read $fi, $buf, $len_of_N;
my $ixf = unpack("N", $buf);
my $ixt = (tell $fi < $ifsz) ? do {
    read $fi, $buf, $len_of_N;
    unpack("N", $buf);
} : $tfsz;
close $fi;

open(my $fh, "<", $tgtfn) or die;
seek $fh, $ixf, 0;
read $fh, $buf, $ixt - $ixf;
close $fh;

print $buf;

■実行例:
% ./getline.pl 2 test.dic
Yokohama

速度比較


実際に取り出し速度を測定して比較してみた。
使ったデータは60Mバイト3万行のテキストファイル。
指定した200行を取り出すタスク(プログラムを200回起動する)。
それぞれの実行時間を測定した。

結果:インデックスを使う手法の方が頭から走査する手法よりも10倍高速であった。

補足


- なぜ「$len_of_N = 4」なのかというと、pack の N は 32ビット(4バイト)ゆえ。"perldoc -f pack" に書いてある。(追記100811

関連記事


- [を] 文字列の ID 化と相互変換を SUFARY を使って行う方法[2008-04-10-2]
- インデックスを使った指定行取り出しプログラム(Pure Ruby) - Maeの(Mae向きな)日記
http://d.hatena.ne.jp/rahaema/20100811#p1

出版社より献本いただきました。ありがとうございます。

竹川美奈子 / 投資信託にだまされるな![新版]

人気の投資信託にはプロの仕掛けた巧妙なワナがたくさん隠されている。本書では、広告例を通じて「投信のワナ」の見破り方を解説し、その後に、数少ない良質な投信の使い方をやさしく解説した。

2007年に出た「投資信託にだまされるな!」[2008-05-19-1]ですが、3年の時を経て新版が登場しました!
ここ2,3年、インデックスファンドが結構出ているので、それらも踏まえた内容っぽいです。
この記事に言及しているこのブログ内の記事

たつをの ChangeLog
Powered by chalow