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

如何在Perl中读取多个目录和子目录的内容?,perl,recursion,readdir,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 =

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

您没有在
print\u file\u names()
函数中提取提供的
$file
参数

应该是:

sub print_file_names()
{
    my $file = shift;
    ...
}
顺便说一句,你在外循环中的
-d
测试看起来也错了。你说的是
下一个if-d…
,这意味着它将跳过目录的内循环,这似乎与你的要求完全相反。它工作的唯一原因是因为您正在测试
$file
,它只是相对于路径的文件名,而不是完整的路径名

另请注意:

  • Windows上的Perl可以使用
    /
    作为路径分隔符
  • 设置父目录一次,然后从该目录派生其他路径
  • 使用
    opendir($scalar,$path)
    而不是
    opendir(DIR,$path)
  • 注意:未经测试的代码如下:

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

    您没有在
    print\u file\u names()
    函数中提取提供的
    $file
    参数

    应该是:

    sub print_file_names()
    {
        my $file = shift;
        ...
    }
    
    顺便说一句,你在外循环中的
    -d
    测试看起来也错了。你说的是
    下一个if-d…
    ,这意味着它将跳过目录的内循环,这似乎与你的要求完全相反。它工作的唯一原因是因为您正在测试
    $file
    ,它只是相对于路径的文件名,而不是完整的路径名

    另请注意:

  • Windows上的Perl可以使用
    /
    作为路径分隔符
  • 设置父目录一次,然后从该目录派生其他路径
  • 使用
    opendir($scalar,$path)
    而不是
    opendir(DIR,$path)
  • 注意:未经测试的代码如下:

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

    你考虑过使用吗


    您考虑过使用

    请开始放:

    use strict;
    use warnings;
    
    在所有脚本的顶部,它将帮助您避免此类问题,并使代码更具可读性

    您可以在此处阅读更多信息:

    请开始放置:

    use strict;
    use warnings;
    
    在所有脚本的顶部,它将帮助您避免此类问题,并使代码更具可读性


    您可以在此处阅读更多信息:

    您发布的代码看起来过于复杂。看看吧,你可以用很少的代码完成大部分繁重的工作

    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";
    }
    

    将应用此限制

    您发布的代码看起来过于复杂。看看吧,你可以用很少的代码完成大部分繁重的工作

    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";
    }
    

    将应用此限制

    您需要更改整个代码以使其健壮:

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

    您需要更改整个代码以使其健壮:

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

    这里有一种方法不需要使用File::Find:

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

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

    最后一步是编写代码来处理这个foreach循环中的文件


    特别感谢我的老师给了我这个想法:)它真的很好用

    这里有一种方法不需要使用File::Find:

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

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

    最后一步是编写代码来处理这个foreach循环中的文件


    特别感谢我的老师给了我这个想法:)它真的很好用

    提示:更喜欢使用“我的”而不是“我们的”,并使用-w选项运行perl(如果可能的话,使用strict)。这将有助于更早地显示此错误:使用“my”但不使用strict,它会警告您“$file”未定义,使用strict,它会在运行之前终止,并说“$file”未声明。提示:更喜欢使用“my”而不是“our”,并使用-w选项运行perl(如果可能的话,还可以使用“use strict”)。这将有助于更早地显示此错误:使用“my”但不使用strict,它会警告您“$file”未定义,使用strict,它会在运行之前停止运行,说“$file”未声明。name(*.html)与他的正则表达式不匹配。幸运的是,name()接受正则表达式和全局表达式。我已经修复了匹配的条件。这将在树中查找级别1和3+的文件(如果存在),这与他的要求相反…@Alnitak:为搜索设置mindepth和maxdepth很容易。name(*.html)与他的正则表达式不匹配。幸运的是,name()接受正则表达式和全局表达式。我已经修正了匹配的条件。这将在树中找到1级和3+级的文件(如果存在的话),这与他的要求相反…@Alnitak:为搜索设置mindepth和maxdepth很容易。对于那些因为我没有使用File::find-a而否决我的人,我正在向他展示如何正确使用opendir等,b)他只指定了两个级别的目录,所有文件都是2级的。而且-错误甚至不在opendir代码中,而是在print_file_names()中!!我给你投了正确的票