Чтение строки с конкретным номером
Проблема
Требуется извлечь из файла строку с известным номером.
Решение
Простейший выход — читать строки до обнаружения нужной:
# Выборка строки с номером $DESIRED_LINE_NUMBER
$. = 0;
do { $LINE = <HANDLE> } until $. == $DESIRED_LINE_NUMBER || eof;
Если подобная операция должна выполняться многократно, а файл занимает не слишком много места в
памяти, прочитайте его в массив:
@lines = <HANDLE>;
$LINE = $lines[$DESIRED_LINE_NUMBER];
Если вы собираетесь многократно извлекать строки по номеру, а файл не помещается в памяти,
постройте индекс смещений для отдельных строк и переходите к началу строки функцией
seek:
# Применение: build_index(*МАНИПУЛЯТОР_ДАННЫХ, *МАНИПУЛЯТОР_ИНДЕКСА)
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);
}
}
# Применение line_with_index(*МАНИПУЛЯТОР_ДАННЫХ, *МАНИПУЛЯТОР_ИНДЕКСА,
$НОМЕР_СТРОКИ)
# Возвращает строку или undef, если НОМЕР_СТРОКИ выходит за пределы файла
sub line_with_index {
my $data_file = shift;
my $index_file = shift;
my $line_number = shift;
my $size; # Размер элемента индекса
my $i_offset; # Смещение элемента в индексе
my $entry; # Элемент индекса
my $d_offset; # Смещение в файле данных
$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>);
}
# Применение:
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);
$line = line_with_index(*FILE, *INDEX, $seeking);
При наличии модуля DB_File можно воспользоваться методом DB_RECNO, который связывает массив с
файлом (по строке на элемент массива):
use DB_File;
use Fcntl;
$tie = tie(@lines, $FILE, O_RDWR, 0666, $DB_RECNO) or die
"Cannot open file $FILE: $!\n";
# Извлечь строку
$line = $lines[$sought-1];
Комментарий
Каждый вариант имеет свои особенности и может пригодиться в конкретной ситуации. Линейное
чтение легко программируется и идеально подходит для коротких файлов. Индексный метод обеспечивает
ускоренную выборку, но требует предварительного построения индекса. Он применяется в случаях,
когда индексируемый файл редко изменяется по сравнению с количеством просмотров. Механизму
DB_File присущи некоторые начальные издержки, зато последующая выборка строк выполняется
намного быстрее, чем при линейном чтении. Обычно он применяется для многократных обращений
к большим файлам.
Необходимо знать, с какого числа начинается нумерация строк — с 0 или 1. Переменной $. \
присваивается 1 после чтения первой строки, поэтому при линейном чтении нумерацию желательно
начинать с 1. В индексном механизме широко применяются смещения, и нумерацию лучше начать с 0.
DB_File интерпретирует записи файла как элементы массива, индексируемого с 0, поэтому строки
также следует нумеровать с 0.
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|