2009-05-18 4 views
1

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

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"); 
    } 
+0

совет: предпочитайте использовать «мой» для «нашего» и запускать perl с параметром -w (и «используйте строгую», если это вообще возможно). что помогло бы выявить эту ошибку раньше: используя «мой», но без строгой, он предупредил бы вас, что «$ file» не определен, и со строгим он умер бы до запуска, заявив, что «$ file» не был объявлен. – araqnid

ответ

4

Вы не извлекая прилагаемое $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"); 
} 
+0

ur great .... thanks alot dude ... – User1611

+1

Для всех тех, кто отказался от использования файла File :: Find - a) Я показывал ему, как правильно использовать opendir и т. Д., И б) он указал только два уровни каталогов, причем все файлы находятся на уровне 2. – Alnitak

+0

также - ошибки были даже не в коде opendir, они были в print_file_names() !! – Alnitak

3

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

use strict; 
use warnings; 

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

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

6

Опубликованная код выглядит путь усложненной. Проверьте 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"; 
} 

Применить это ограничение.

+1

name ("*. Html") не соответствует тем же файлам, что и его регулярное выражение. К счастью, name() принимает регулярные выражения, а также глобусы. Я исправил условие для соответствия. – cjm

+0

, и это найдет файлы (если они существуют) на уровнях 1 и 3+ в дереве, в отличие от его требований ... – Alnitak

+0

@Alnitak: его легко установить мышление и maxdepth для поиска. –

3

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

#!/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__ 
0

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

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

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

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

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

Смежные вопросы