Чтение определенной строки за номером строки в очень большом файле

Файл не помещается в память. Это более 100 ГБ, и я хочу получить доступ к определенным строкам по номеру строки. Я не хочу считать построчно, пока не дойду.

Я прочитал 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 не читает файл в массив правильно?


person user1645240    schedule 27.09.2012    source источник
comment
Линии фиксированной или переменной длины?   -  person Len Jaffe    schedule 27.09.2012
comment
Я не хочу считать строку за строкой, пока не достигну ее. Если это строки переменной длины, у вас нет выбора.   -  person Sean Bright    schedule 27.09.2012
comment
Похоже, вам было бы полезно использовать базу данных вместо файла.   -  person TLP    schedule 27.09.2012


Ответы (1)


pack N создает 32-битное целое число. Максимальное 32-битное целое число составляет 4 ГБ, поэтому его использование для хранения индексов в файле размером 100 ГБ не сработает.

В некоторых сборках используются 64-битные целые числа. На них вы можете использовать j.

В некоторых сборках используются 32-битные целые числа. tell возвращает для них число с плавающей запятой, что позволяет без потерь индексировать файлы размером до 8 388 608 ГБ. На них вы должны использовать F.

Переносимый код будет выглядеть следующим образом:

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

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

Примечание. Я предполагаю, что индексный файл используется только тем же Perl, который его построил (или, по крайней мере, файлом с таким же целочисленным размером, размером поиска и машинным порядком байтов). Дайте мне знать, если это предположение вас не устраивает.

person ikegami    schedule 27.09.2012
comment
Вопрос не поддерживается. Выдает ошибку: Неверный тип 'Q' в пакете в строке 21 buildIndex.pl, ‹FILE› в строке 1. - person user1645240; 27.09.2012
comment
Да, индексный файл можно использовать только с тем же Perl, на котором он был создан. Я действительно не понимаю портативный код или что с ним делать. Я новичок в перле. Мне просто изменить все N на j или F? - person user1645240; 27.09.2012
comment
Он проверяет, как ваш Perl был настроен для генерации правильного формата. Используйте $off_t вместо "N". В вашем случае это будет F. - person ikegami; 27.09.2012