如何在Perl中读取多个目录并读取子目录的内容?

时间:2009-05-18 14:49:38

标签: perl recursion readdir

我有一个文件夹,里面有很多子文件夹。在这些子文件夹中,我有许多.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 个答案:

答案 0 :(得分: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";
}

我的意思是不那么性感吗?!

用户评论说您可能希望仅使用Depth = 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 :(得分:4)

您未在$file函数中提取提供的print_file_names()参数。

应该是:

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

外环中的-d测试看起来也不对,BTW。你说的是next if -d ...,这意味着它会跳过目录的内部循环,这似乎与你需要的完全相反。它工作的唯一原因是因为你正在测试$file,它只是相对于路径的文件名,而不是完整的路径名。

另请注意:

  1. Windows上的Perl可以很好地处理/作为路径分隔符
  2. 设置您的父目录一次,然后从该
  3. 派生其他路径
  4. 使用opendir($scalar, $path)代替opendir(DIR, $path)
  5. 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");
     }
    

答案 2 :(得分:3)

请开始点击:

use strict;
use warnings;

位于所有脚本的顶部,它将帮助您避免此类问题并使您的代码更具可读性。

您可以在此处详细了解:Perlmonks

答案 3 :(得分: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__

答案 4 :(得分:1)

您是否考虑过使用

File::Find

答案 5 :(得分:0)

这是一种不需要使用File :: Find:

的方法

首先打开根目录,然后使用readdir将所有子文件夹的名称存储在数组中;

然后,使用foreach循环。对于每个子文件夹,通过链接根目录和文件夹名称来打开新目录。仍然使用readdir将文件名存储在数组中。

最后一步是编写处理foreach循环内文件的代码。

特别感谢我的老师给了我这个想法:)真的很有效!