Чтение строки с конкретным номером

Проблема

Требуется извлечь из файла строку с известным номером.

Решение

Простейший выход — читать строки до обнаружения нужной:
# Выборка строки с номером $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.

См. также




2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: