Как мне прочитать несколько каталогов и прочитать содержимое подкаталогов в Perl? - PullRequest
1 голос
/ 18 мая 2009

У меня есть папка, и внутри нее у меня много подпапок. В этих подпапках у меня есть много файлов .html для чтения. Я написал следующий код, чтобы сделать это. Он открывает родительскую папку, а также первую подпапку и печатает только один файл .html. Это показывает ошибку:

NO SUCH FILE OR DIRECTORY

Я не хочу менять весь код. Любые изменения в существующем коде будут мне полезны.

 use FileHandle;
 opendir PAR_DIR,"D:\\PERL\\perl_programes\\parent_directory";
 while (our $sub_folders = readdir(PAR_DIR))
 {
         next if(-d $sub_folders);

         opendir SUB_DIR,"D:\\PERL\\perl_programes\\parent_directory\\$sub_folders";
         while(our $file = readdir(SUB_DIR))
         {

       next if($file !~ m/\.html/i);
            print_file_names($file);    
         }
         close(FUNC_MODEL1);    
 }
 close(FUNC_MODEL);

  sub print_file_names()
  {
     my $fh1 = FileHandle->new("D:\\PERL\\perl_programes\\parent_directory\\$file")  
               or die "ERROR: $!"; #ERROR HERE 
     print("$file\n");
  }

Ответы [ 6 ]

6 голосов
/ 18 мая 2009

Ваш опубликованный код выглядит слишком сложным. Проверьте File :: Find :: Rule , и вы можете выполнить большую часть этой тяжелой работы с помощью небольшого кода.

use File::Find::Rule;

my $finder = File::Find::Rule->new()->name(qr/\.html?$/i)->start("D:/PERL/perl_programes/parent_directory");

while( my $file = $finder->match()  ){
   print "$file\n";
}

Я имею в виду разве это не сексуально?!

Пользователь заметил, что вы можете использовать только глубину = 2 записи.

use File::Find::Rule;

my $finder = File::Find::Rule->new()->name(qr/\.html?$/i)->mindepth(2)->maxdepth(2)->start("D:/PERL/perl_programes/parent_directory");

while( my $file = $finder->match()  ){
   print "$file\n";
}

Будет применять это ограничение.

4 голосов
/ 18 мая 2009

Вы не извлекаете предоставленный параметр $file в функции print_file_names().

Должно быть:

sub print_file_names()
{
    my $file = shift;
    ...
}

Ваш тест -d во внешнем цикле тоже выглядит неправильно, кстати. Вы говорите next if -d ..., что означает, что он пропустит внутренний цикл для каталогов, который, кажется, является полной противоположностью того, что вам требуется. Единственная причина, по которой он работает, это то, что вы тестируете $file, которое является только именем файла относительно пути, а не полным именем пути.

Примечание также:

  1. Perl в Windows прекрасно справляется с / в качестве разделителя пути
  2. Установите родительский каталог один раз, а затем извлекайте другие пути из этого
  3. Используйте opendir($scalar, $path) вместо opendir(DIR, $path)

nb: непроверенный код следует:

use strict;
use warnings;
use FileHandle;

my $parent = "D:/PERL/perl_programes/parent_directory";

my ($par_dir, $sub_dir);
opendir($par_dir, $parent);
while (my $sub_folders = readdir($par_dir)) {
    next if ($sub_folders =~ /^..?$/);  # skip . and ..
    my $path = $parent . '/' . $sub_folders;
    next unless (-d $path);   # skip anything that isn't a directory

    opendir($sub_dir, $path);
    while (my $file = readdir($sub_dir)) {
        next unless $file =~ /\.html?$/i;
        my $full_path = $path . '/' . $file;
        print_file_names($full_path);    
    }
    closedir($sub_dir);
}
closedir($par_dir);

sub print_file_names()
{
     my $file = shift;
     my $fh1 = FileHandle->new($file) 
           or die "ERROR: $!"; #ERROR HERE 
     print("$file\n");
 }
3 голосов
/ 18 мая 2009

Вам нужно изменить весь код, чтобы сделать его устойчивым:

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;

my $top = $ENV{TEMP};

find( { wanted => \&wanted, no_chdir=> 1 }, $top );

sub wanted {
    return unless -f and /\.html$/i;
    print $_, "\n";
}

__END__
3 голосов
/ 18 мая 2009

Пожалуйста, начните вводить:

use strict;
use warnings;

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

Подробнее об этом можно прочитать здесь: Perlmonks

1 голос
/ 18 мая 2009

Рассматривали ли вы использование

File :: Find

0 голосов
/ 20 августа 2015

Вот один метод, который не требует использования File :: Find:

Сначала откройте корневой каталог и сохраните имена всех подпапок в массиве с помощью readdir;

Затем используйте цикл foreach. Для каждой подпапки откройте новый каталог, связав корневой каталог и имя папки. Все еще используйте readdir для хранения имен файлов в массиве.

Последний шаг - написать коды для обработки файлов внутри этого цикла foreach.

Отдельное спасибо моему учителю, который дал мне эту идею :) Это действительно сработало!

...