изменить способ работы readdir (сначала последний файл)

У меня есть каталог, содержащий n файлов, все из которых соответствуют шаблону /^\d\d\d\d$/, через который я иду с while (my $file = readdir ($DIR) ) { ... }, чтобы избежать одновременного чтения всего каталога в ОЗУ. В этом цикле я подсчитываю файлы (исключая каталоги и файлы без соответствующих имен) и выбираю пять файлов, начиная с указанной точки, и читаю первые две строки каждого файла в массив.

На самом деле у меня два вопроса:

  1. Можно ли запустить цикл с последнего файла в каталоге, начиная с файла с самым большим именем файла и возвращаясь «назад»? (Я предполагаю, что каждая ОС будет возвращать эти файлы в порядке 0000 -> 0001 -> 0002...)

  2. Поскольку это было бы намного проще, насколько плохо было бы просто прочитать весь каталог в массиве по сравнению с просмотром всего списка один за другим?

Полный блок кода:

while ( my $f = readdir ($DIR) ){

    print "checking " .  $f . "\n";
    next unless -f ($dir . "/" . $f);
    next unless $f =~ /^\d\d\d\d$/;

    $c++;

    if ( $c >= $index && $c <= $index + 4 ){
        open (my $ITM, "<", "$dir/$f") or die "Opening file $f in $dir failed:$!\n";
            my $headline = <$ITM>; my $first_p = <$ITM>;
        close $ITM;

            chomp ($headline, $first_p);
            push (@content, $headline, $first_p); 

        print $f . " was checked succesfully!\n";
    }
}

заранее спасибо


person user7183174    schedule 19.11.2016    source источник
comment
Проблемы с форматированием были вызваны тем, что вы использовали теги <pre><code> (встроенный HTML) вместо простого отступа (что является синтаксисом Markdown для блоков кода).   -  person melpomene    schedule 19.11.2016
comment
Я бы порекомендовал выполнить проверку шаблона перед проверкой -f... Таким образом, вы избежите дорогостоящего вызова stat для имен, не соответствующих шаблону.   -  person Sinan Ünür    schedule 19.11.2016
comment
С технической точки зрения ваше регулярное выражение соответствует большому количеству строк, которые вы, вероятно, не собирались сопоставлять; например $ допускает перевод строки в конце имени, а \d соответствует любой цифре Unicode (не только 0-9). Я бы использовал /\A\d{4}\z/a (или /\A[0-9]{4}\z/, если в вашем Perl еще нет /a).   -  person melpomene    schedule 19.11.2016
comment
Если вы в конечном итоге прочитаете их в массиве (основываясь на ответах ниже), вы можете получить только 4-символьные имена файлов как: my @files = ‹????›, а затем проверить, являются ли они числовыми.   -  person deepakg    schedule 19.11.2016
comment
@deepakg Хороший вопрос. Вы даже можете сделать glob('[0-9]' x 4), чтобы просто получить числовые имена.   -  person melpomene    schedule 19.11.2016


Ответы (2)


  1. Файловые системы обычно возвращают записи каталога в непредсказуемом порядке. Они не будут отсортированы по алфавиту. (За исключением, возможно, Windows? Не уверен.)

  2. Даже если у вас есть миллион файлов в этом каталоге, это просто «мега». Таким образом, если для хранения каждого имени требуется 10 байт, это всего лишь 10 МБ ОЗУ. Ладно, во внутренних структурах данных Perl есть некоторые накладные расходы, но почти наверняка у вас будет меньше имен, чем миллион. Так что я бы сказал, что это совсем не плохо.

person melpomene    schedule 19.11.2016
comment
Даже не в Windows. См. раздел FindNextFile: Порядок, в котором поиск возвращает файлы, например в алфавитном порядке, не гарантируется и зависит от файловой системы. Если данные должны быть отсортированы, приложение должно упорядочить их после получения всех результатов. - person Sinan Ünür; 19.11.2016
comment
@SinanÜnür Спасибо, это приятно знать. Там написано Для файловой системы NTFS... имена обычно возвращаются в алфавитном порядке, вероятно, это то, что я видел в своих тестах, но, конечно, это не гарантируется. - person melpomene; 19.11.2016
comment
Итак, если я хочу иметь (надежно) один файл и четыре следующих файла, у меня нет другого выбора, кроме как прочитать их в массиве и отсортировать? Спасибо за подсказку по NTFS, мне было интересно, почему у меня все время работало... - person user7183174; 19.11.2016
comment
@ user7183174 Это определенно самый простой способ. Существуют более сложные алгоритмы для выбора, например. 5 самых маленьких или 5 самых больших элементов из списка за линейное время и постоянную память, но это, вероятно, требует больше усилий, чем оно того стоит. - person melpomene; 19.11.2016
comment
@SinanÜnür Да, понял, просто хотел уточнить, почему я до сих пор не заметил этой проблемы. - person user7183174; 19.11.2016

Используйте glob(), чтобы получить список файлов.

my @files = grep /\/\d{4}$/, glob( "$dir/*" );

Затем вы можете отсортировать их в любом порядке.

person shawnhcorey    schedule 20.11.2016