Как я могу получить список всех файлов с определенным расширением из определенного каталога?

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

opendir DIR, $dir or die "cannot open dir $dir: $!";
my @files= readdir DIR;
closedir DIR;

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

Пример содержимого каталога:

.
..
923847.txt
98398523.txt
198.txt
deisi.jpg
oisoifs.gif
lksdjl.exe

Пример содержимого массива:

files[0]=923847 
files[1]=98398523
files[2]=198

person CheeseConQueso    schedule 02.10.2009    source источник
comment
Также рассмотрите возможность использования лексической переменной для дескриптора вашего каталога: opendir my $dirh, $dir_path or die "cannot open dir $dir: $!";   -  person Robert P    schedule 02.10.2009


Ответы (6)


достаточно изменить одну строчку:

my @files= map{s/\.[^.]+$//;$_}grep {/\.txt$/} readdir DIR;
person catwalk    schedule 02.10.2009

Если вы можете использовать новые возможности Perl 5.10, я бы написал его так.

use strict;
use warnings;
use 5.10.1;
use autodie; # don't need to check the output of opendir now

my $dir = ".";

{
  opendir my($dirhandle), $dir;
  for( readdir $dirhandle ){ # sets $_
    when(-d $_ ){ next } # skip directories
    when(/^[.]/){ next } # skip dot-files

    when(/(.+)[.]txt$/){ say "text file: ", $1 }
    default{
      say "other file: ", $_;
    }
  }
  # $dirhandle is automatically closed here
}

Или, если у вас очень большие каталоги, вы можете использовать цикл while.

{
  opendir my($dirhandle), $dir;
  while( my $elem = readdir $dirhandle ){
    given( $elem ){ # sets $_
      when(-d $_ ){ next } # skip directories
      when(/^[.]/){ next } # skip dot-files

      when(/(.+)[.]txt$/){ say "text file: ", $1 }
      default{
        say "other file: ", $_;
      }
    }
  }
}
person Brad Gilbert    schedule 02.10.2009

Это самый простой способ, который я нашел (как в удобочитаемом человеке), используя функцию glob:

 # Store only TXT-files in the @files array using glob
 my @files = grep ( -f ,<*.txt>);
 # Write them out
 foreach $file (@files) {
  print "$file\n";
 }

Кроме того, «-f» гарантирует, что в массиве хранятся только фактические файлы (а не каталоги).

person Kebman    schedule 22.12.2012
comment
Зачем откатывать редактирование? foreach $file не является строго безопасным. Если вы предпочитаете foreach for, почему не foreach my $file? - person Benjamin W.; 27.07.2015
comment
Зачем редактировать чужие старые вещи, если вы не знаете, почему они вообще были опубликованы? Черт, я даже не знаю причину, по которой я написал этот фрагмент кода более трех лет назад, но, поскольку у меня есть привычка тестировать, он, вероятно, работал нормально, и, вероятно, есть причина, по которой я не добавил строгий декларации тоже. Однако означает ли это, что я должен просто принять случайное изменение и хочу ли я вообще тратить время на его тестирование? Конечно нет! Вот почему я счел гораздо безопаснее просто откатить его. - person Kebman; 28.07.2015
comment
Чтобы было ясно, это не я редактировал, я просто увидел правку и подумал, что это улучшило ответ. Просто странно, что вы используете лексический @files, а затем глобальный $file. - person Benjamin W.; 28.07.2015
comment
Прочтите это так, как будто это по-английски: для каждого файла в списке файлов сделайте что-нибудь с каждым файлом в списке (например, распечатайте каждую запись в файле). Я люблю английский, потому что большинство людей его понимают. Я все еще не собираюсь даже пытаться улучшить его сам, и я собираюсь откатить все другие попытки, потому что я не хочу проверять чужие странные изменения в моем коде. Однако, если это действительно так хреново, я могу полностью удалить свой ответ. Вместо этого используйте мой код и опубликуйте свой ответ. Я имею в виду, это не похоже на то, что это защищено авторским правом или что-то в этом роде, так что вперед. :) - person Kebman; 30.07.2015
comment
›И, вероятно, есть причина, по которой я не добавил в строгую декларацию. Буквально нет веских причин не придерживаться строгих правил. Проголосовали против. - person Franz Kafka; 06.10.2017

Чтобы получить только файлы «.txt», вы можете использовать оператор проверки файлов (-f: обычный файл) и регулярное выражение.

my @files = grep { -f && /\.txt$/ } readdir $dir;

В противном случае вы можете искать только текстовые файлы, используя perl -T (оператор проверки текстового файла ascii)

my @files = grep { -T } readdir $dir;
person Robert P    schedule 02.10.2009
comment
-T - для проверки, есть ли у вас текстовый файл - person reinierpost; 02.10.2009
comment
Хорошая точка зрения; со страницы perldoc на операторе (perldoc.perl.org/5.8.8/perlfunc. html), -T File - текстовый файл ASCII (эвристическое предположение). если он ищет файлы .txt, он сделает именно то, что он просит, не догадываясь. - person Robert P; 02.10.2009

Просто используйте это:

my @files = map {-f && s{\.txt\z}{} ? $_ : ()} readdir DIR;
person Hynek -Pichi- Vychodil    schedule 02.10.2009

person    schedule
comment
есть идеи, как повторно использовать каталог? мой вывод / dir / dir / dir / 923847 ... как я могу просто получить 923847? - person CheeseConQueso; 02.10.2009
comment
glob добавляет сюда дополнительную работу. См. stackoverflow.com/questions/1506801/ - person brian d foy; 02.10.2009