Как манипулировать указателем файла в Perl

Поэтому я читаю файл календаря, чтобы вставить дату в файл, и я хочу, чтобы даты оставались в хронологическом порядке. Проблема возникает, когда я нахожу место, куда должна идти дата, файл уже просматривает точку, в которую я хочу вставить.

Файл календаря, на который я смотрю, выглядит так:

# November 2010
11/26/2010
11/27/2010
11/28/2010
11/29/2010
11/30/2010
# December
12/24/2010
12/25/2010
12/26/2010
12/27/2010
12/28/2010
12/29/2010
12/30/2010

и мой код выглядит так:

while (my $line = <FILE>) {
    if (substr($line, 0, 1) =~ m/\#/ || $line =~ m/calendar/) { #if the line is commented out or contains the calendar's name skip to next line
        next;
    }
    chomp($line);
    my ($temp_month, $temp_day, $temp_year) = split(/\//, $line, 3);
    if ($year == $temp_year && $month == $temp_month && $day < $temp_day) {
        ?
    }
}

Так есть ли какие-либо предложения относительно того, как указать на предыдущее место в файле?

4 ответа

Решение

Функция, которая вам нужна для случайного перемещения по файлу - это поиск. Но есть больше информации о том, как решить эту проблему в Perl FAQ - Как мне изменить, удалить или вставить строку в файл или добавить в начало файла?

Это звучит как отличное применение для модуля Tie::File. Вы можете обрабатывать файл как массив и не беспокоиться о текущей позиции указателя файла. Это также не зависит от загрузки всего файла в память - поэтому оно будет работать с массивными файлами.

use Tie::File;

tie @array, 'Tie::File', $file;

for (my $i =0; $i <= @array; $i++) {
    if (/date comparison/*see note below) {
        splice @array, $i, 0, $new_date;
    }
}

Это позволит вам использовать функции массива perl, например, splice, для вставки новых строк.

Но у вас также есть большая проблема с вашей стратегией сравнения дат. Что, если в файле еще нет дат для данного месяца, года? Вы пройдете через и не найдете для этого места. Проверьте timelocal, который вы можете использовать, чтобы преобразовать обе даты в время эпохи, а затем сравнить их.

use Time::Local;
my $temp_epoch = timelocal(0,0,0,$temp_day,$temp_month -1, $temp_year-1900);
if ($epoch < $temp_epoch ) {
    ...
}

искать и рассказать решит проблему сворачивания назад. В итоге вы перезапишете существующие строки. Ленивое решение состоит в том, чтобы использовать Tie:: File, еще одну возможность - прочитать файл во время записи новой версии, а затем заменить старую версию новой, когда вы закончите.

Стандартное решение perl - бросить память на проблему:

открыть (мой $FILE, ....);   # открыть в режиме чтения / записи
my @lines = ; #slurp во всех строках файла... вставить (или удалить?) в массив...
усечь ( $FILE, 0);    # при удалении вам нужно будет обрезать
искать ( $FILE, 0, 0);
выведите $FILE @lines;

Чтобы быть более эффективным, вы могли бы просто писать с точки изменения, а не со всего, но если скорость не важна, простота имеет меньший потенциал ошибок.

Другие вопросы по тегам