【问题标题】:How to traverse all the files in a directory; if it has subdirectories, I want to traverse files in subdirectories too如何遍历一个目录下的所有文件;如果它有子目录,我也想遍历子目录中的文件
【发布时间】:2012-03-07 11:14:11
【问题描述】:
opendir(DIR,"$pwd") or die "Cannot open $pwd\n";
    my @files = readdir(DIR);
    closedir(DIR);
    foreach my $file (@files) {
        next if ($file !~ /\.txt$/i);
        my $mtime = (stat($file))[9];
        print $mtime;
        print "\n";
    }

基本上我想记下一个目录中所有 txt 文件的时间戳。如果有子目录,我也想在该子目录中包含文件。

谁能帮我修改上面的代码,让它也包含子目录。

如果我在 Windows 中使用下面的代码,我会获取文件夹中所有文件的时间戳,甚至在我的文件夹之外

 my @dirs = ("C:\\Users\\peter\\Desktop\\folder");
    my %seen;
    while (my $pwd = shift @dirs) {
            opendir(DIR,"$pwd") or die "Cannot open $pwd\n";
            my @files = readdir(DIR);
            closedir(DIR);
            #print @files;
            foreach my $file (@files) {
                    if (-d $file and !$seen{$file}) {
                            $seen{$file} = 1;
                            push @dirs, "$pwd/$file";
                    }
                    next if ($file !~ /\.txt$/i);
                    my $mtime = (stat("$pwd\$file"))[9];
                    print "$pwd $file $mtime";
                    print "\n";
            }
    }

【问题讨论】:

    标签: perl directory-traversal


    【解决方案1】:

    File::Find 最适合这个。它是一个核心模块,所以不需要安装。这段代码和你想象的一样

    use strict;
    use warnings;
    
    use File::Find;
    
    find(sub {
      if (-f and /\.txt$/) {
        my $mtime = (stat _)[9];
        print "$mtime\n";
      }
    }, '.');
    

    其中'.'是要扫描的目录树的根;如果你愿意,你可以在这里使用$pwd。在子例程中,Perl 对找到文件的目录执行了chdir$_ 设置为文件名,$File::Find::name 设置为包含路径的全限定文件名。

    【讨论】:

    • Not everybody will agree with you on File::找到最好的。
    • File::Find 很慢,API 也很令人沮丧,但我认为它非常适合这种琐碎的事情。我想听听有人反对它。
    • @salva 很老的评论我知道,但链接现在指向登录页面。
    【解决方案2】:
    use warnings;
    use strict;
    
    my @dirs = (".");
    my %seen;
    while (my $pwd = shift @dirs) {
            opendir(DIR,"$pwd") or die "Cannot open $pwd\n";
            my @files = readdir(DIR);
            closedir(DIR);
            foreach my $file (@files) {
                    next if $file =~ /^\.\.?$/;
                    my $path = "$pwd/$file";
                    if (-d $path) {
                            next if $seen{$path};
                            $seen{$path} = 1;
                            push @dirs, $path;
                    }
                    next if ($path !~ /\.txt$/i);
                    my $mtime = (stat($path))[9];
                    print "$path $mtime\n";
            }
    }
    

    【讨论】:

    • $file !~ /^\.*$/$file =~ /[^.]/。但我过去曾因排除仅三个点或更长的名称而受到严厉谴责,因为它们是 Linux 文件的有效名称。所以测试应该$file !~ /^\.\.?$/
    • @perreal 如果我想打开文件并在文件中搜索一些特定的字符串并分隔这些文件,我想用 OPEN INPUT, $file 然后 $lines = 然后搜索它,好吗?或者还有其他简单的方法
    • 您可以使用grep。如果您不想使用任何工具,那么按照您的建议去做就可以了。
    • 嗨,你们都可以看到编辑过的问题并帮助我吗.. 我在 windows 中尝试了代码,但我也得到了位于我指定文件夹之外的文件夹中的文件的时间戳,我已经粘贴了有问题的代码
    • 你能试试这些改变吗? push @dirs, "$pwd\\$file"; my $mtime = (stat("$pwd\\$file"))[9];
    【解决方案3】:

    使用File::Find::Rule

    File::Find::Rule 是 File::Find 的一个更友好的界面。它允许您构建指定所需文件和目录的规则。

    【讨论】:

      【解决方案4】:

      您可以使用递归:定义一个遍历文件并在目录上调用自身的函数。然后调用顶层目录的函数。

      另见File::Find

      【讨论】:

      • 如何区分目录中的文件和目录
      • @Peter:使用-d-f 运算符,记录在案的here
      【解决方案5】:

      如果我在 Windows 中使用下面的代码,我会获取文件夹中所有文件的时间戳,甚至在我的文件夹之外

      我怀疑问题可能出在... 目录上,如果您尝试关注它们,您会向上 进入目录树。您缺少的是:

      foreach my $file (@files) {
          # skip . and .. which cause recursion and moving up the tree
          next if $file =~ /^\.\.?$/;
          ...
      

      您的脚本也存在一些错误。 $file$dir 无关,因此 -d $file 只能在当前目录中工作,而不是在下面。

      这是我的固定版本:

      use warnings;
      use strict;
      
      # if unix, change to "/";
      my $FILE_PATH_SLASH = "\\";    
      my @dirs = (".");
      my %seen;
      while (my $dir = shift @dirs) {
              opendir(DIR, $dir) or die "Cannot open $dir\n";
              my @files = readdir(DIR);
              closedir(DIR);
              foreach my $file (@files) {
                      # skip . and ..
                      next if $file =~ /^\.\.?$/;
                      my $path = "$dir$FILE_PATH_SLASH$file";
                      if (-d $path) {
                              next if $seen{$path};
                              $seen{$path} = 1;
                              push @dirs, $path;
                      }
                      next unless $path ~= /\.txt$/i;
                      my $mtime = (stat($path))[9];
                      print "$path $mtime\n";
              }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-08-01
        • 2021-07-09
        • 2015-03-05
        • 1970-01-01
        • 2013-10-09
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        相关资源
        最近更新 更多