在非常大的文件中按行号读取特定行

时间:2012-09-27 18:06:14

标签: database perl large-files readlines

该文件不适合内存。它超过100GB,我想按行号访问特定的行。在我到达之前,我不想逐行计算。

我已阅读http://docstore.mik.ua/orelly/perl/cookbook/ch08_09.htm

当我使用以下方法构建索引时,行返回工作到某一点。一旦行号非常大,返回的行就是相同的。当我转到文件中的特定行时,返回相同的行。它似乎适用于行号1到350000(大约);

 # usage: build_index(*DATA_HANDLE, *INDEX_HANDLE) 
    sub build_index {
        my $data_file  = shift;
        my $index_file = shift;
        my $offset     = 0;

        while (<$data_file>) {
            print $index_file pack("N", $offset);
            $offset = tell($data_file);
        }
    }

    # usage: line_with_index(*DATA_HANDLE, *INDEX_HANDLE, $LINE_NUMBER)
    # returns line or undef if LINE_NUMBER was out of range
    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("N", 0));
        $i_offset = $size * ($line_number-1);
        seek($index_file, $i_offset, 0) or return;
        read($index_file, $entry, $size);
        $d_offset = unpack("N", $entry);
        seek($data_file, $d_offset, 0);
        return scalar(<$data_file>);
    }

我也尝试过使用DB_file方法,但似乎需要很长时间才能完成平局。我也不太明白它对“DB_RECNO访问方法将数组绑定到文件,每个数组元素一行”意味着什么。 Tie不会将文件读入数组正确吗?

1 个答案:

答案 0 :(得分:4)

pack N创建一个32位整数。最大32位整数是4GB,因此使用它将索引存储到100GB大小的文件中将不起作用。

某些版本使用64位整数。在那些,您可以使用j

某些版本使用32位整数。 tell返回一个浮点数,允许您无损地索引大小为8,388,608 GB的文件。在那些,你应该使用F

便携式代码如下所示:

use Config qw( %Config );
my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j';

...
print $index_file pack($off_t, $offset);
...

注意:我假设索引文件仅由构建它的相同Perl使用(或者至少一个具有相同整数大小,搜索大小和机器字节顺序的Perl)。如果这个假设不适合你,请告诉我。