【发布时间】:2014-05-31 10:15:09
【问题描述】:
我目前是 Perl 新手,偶然发现了一个问题:
我的任务是创建一种在 Perl 中访问大文件行的简单方法,这是可能的最快方法。 我创建了一个包含 500 万行的文件,每行都有行号。 然后,我创建了需要能够打印给定行的任何内容的主程序。 为此,我使用了我在互联网上找到的两种方法:
use Config qw( %Config );
my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j';
my $file = "testfile.err";
open(FILE, "< $file") or die "Can't open $file for reading: $!\n";
open(INDEX, "+>$file.idx")
or die "Can't open $file.idx for read/write: $!\n";
build_index(*FILE, *INDEX);
my $line = line_with_index(*FILE, *INDEX, 129);
print "$line";
sub build_index {
my $data_file = shift;
my $index_file = shift;
my $offset = 0;
while (<$data_file>) {
print $index_file pack($off_t, $offset);
$offset = tell($data_file);
}
}
sub line_with_index {
my $data_file = shift;
my $index_file = shift;
my $line_number = shift;
my $size; # size of an index entry
my $i_offset; # offset into the index of the entry
my $entry; # index entry
my $d_offset; # offset into the data file
$size = length(pack($off_t, 0));
$i_offset = $size * ($line_number-1);
seek($index_file, $i_offset, 0) or return;
read($index_file, $entry, $size);
$d_offset = unpack($off_t, $entry);
seek($data_file, $d_offset, 0);
return scalar(<$data_file>);
}
这些方法有时有效,我在十次尝试不同的值集时得到一个值,但大多数时候我得到“在 test2.pl 第 10 行的字符串中使用了未初始化的值 $line”(当寻找文件中的第 566 行)或不是正确的数值。此外,索引似乎在前两百行左右工作正常,但后来我得到了错误。我真的不知道我做错了什么..
我知道您可以使用一个基本循环来解析每一行,但我确实需要一种在任何给定时间访问文件的一行而无需重新解析它的方法。
编辑:我尝试使用此处找到的小提示:Reading a particular line by line number in a very large file 我已将 pack 的“N”模板替换为:
my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j';
它使过程更好地工作,直到第 128 行,我没有得到 128 ,而是得到一个空白字符串。对于 129,我得到 3,这并不意味着什么..
Edit2:基本上我需要的是一种机制,使我能够读取接下来的 2 行,例如对于已经被读取的文件,同时将读取的“head”保持在当前行(而不是 2 行之后) .
感谢您的帮助!
【问题讨论】:
-
Re "在 test2.pl 第 46 行的字符串中使用了未初始化的值 $line" 该程序只有 7 行!你实际上得到了什么输出?
-
我没有遇到任何问题,可以使用包含 2GB 数据的文件运行您的脚本。使用包含超过 4GB 的文件的包“N”将是一个问题。使用 pack "J"(大写)来解决这个问题。
-
@imran,错了。他已经在使用的
$Config{lseeksize} > $Config{ivsize} ? 'F' : 'j'好多了。 1) 'j' 更合适,因为 seek since 需要一个有符号数。 2)您的建议在 32 位机器上根本没有帮助(尽管我不确定 'F' 是否也会) -
@imran,如果数字适合 IV,Perl 经常将 UV 转换为 IV。尝试使用不适合 IV 的数字来查看差异。
-
@Hawknight 可以使用数组或内存文件。这完全取决于您的用例。在磁盘上使用索引文件的好处是您不必在每次程序启动时重新读取主文件(除非文件经常更改)。您可以将索引文件读入内存。内存中的数组或其他一些数据结构会更快,但会增加脚本的内存占用。
标签: perl indexing logfile logfile-analysis