【问题标题】:How do I read in the contents of a directory in Perl?如何在 Perl 中读取目录的内容?
【发布时间】:2010-09-06 13:24:54
【问题描述】:

如何让 Perl 将给定目录的内容读入数组?

Backticks 可以做到,但是有没有使用 'scandir' 或类似术语的方法?

【问题讨论】:

    标签: perl file-io filesystems


    【解决方案1】:
    opendir(D, "/path/to/directory") || die "Can't open directory: $!\n";
    while (my $f = readdir(D)) {
        print "\$f = $f\n";
    }
    closedir(D);
    

    编辑:哦,对不起,错过了“进入数组”部分:

    my $d = shift;
    
    opendir(D, "$d") || die "Can't open directory $d: $!\n";
    my @list = readdir(D);
    closedir(D);
    
    foreach my $f (@list) {
        print "\$f = $f\n";
    }
    

    EDIT2:大多数其他答案都是有效的,但我想特别评论this answer,其中提供了这个解决方案:

    opendir(DIR, $somedir) || die "Can't open directory $somedir: $!";
    @dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
    closedir DIR;
    

    首先,记录它在海报上所做的事情:它通过grep() 传递从readdir() 返回的列表,该列表只返回那些是文件的值(而不是目录、设备、命名管道、等等)并且不以点开头(这使得列表名称@dots 具有误导性,但这是由于他在从 readdir() 文档中复制它时所做的更改)。由于它限制了它返回的目录的内容,我认为它在技术上不是这个问题的正确答案,但它说明了用于过滤Perl 中的文件名的常见习语,我认为记录它会很有价值。另一个经常看到的例子是:

    @list = grep !/^\.\.?$/, readdir(D);
    

    这个 sn-p 从目录句柄 D except '.' 中读取所有内容和 '..',因为它们很少需要在列表中使用。

    【讨论】:

      【解决方案2】:

      一个快速而肮脏的解决方案是使用glob

      @files = glob ('/path/to/dir/*');
      

      【讨论】:

      【解决方案3】:

      这将在一行中完成(注意末尾的“*”通配符)

      @files = </path/to/directory/*>;
      # To demonstrate:
      print join(", ", @files);
      

      【讨论】:

      • 有人可以向我解释为什么这是“错误的”吗?因为它干净简单(与其他一些解决方案相反),但它已被降级而没有解释。
      • 我几乎不记得读过 globbing 依赖于所使用的 shell,也许这就是原因。
      • 这是最好的解决方案,它很干净,对我来说效果很好。
      • 不适用于 Mac 上的 perl 5.12,但适用于 perl 5.16。
      【解决方案4】:

      IO::Dir 很好,并且还提供了一个绑定的哈希接口。

      来自 perldoc:

      use IO::Dir;
      $d = IO::Dir->new(".");
      if (defined $d) {
          while (defined($_ = $d->read)) { something($_); }
          $d->rewind;
          while (defined($_ = $d->read)) { something_else($_); }
          undef $d;
      }
      
      tie %dir, 'IO::Dir', ".";
      foreach (keys %dir) {
          print $_, " " , $dir{$_}->size,"\n";
      }
      

      所以你可以这样做:

      tie %dir, 'IO::Dir', $directory_name;
      my @dirs = keys %dir;
      

      【讨论】:

        【解决方案5】:

        你可以使用DirHandle:

        use DirHandle;
        $d = new DirHandle ".";
        if (defined $d)
        {
            while (defined($_ = $d->read)) { something($_); }
            $d->rewind;
            while (defined($_ = $d->read)) { something_else($_); }
            undef $d;
        }
        

        DirHandleopendir()closedir()readdir()rewinddir() 函数提供了一个替代的、更简洁的界面。

        【讨论】:

          【解决方案6】:

          这是一个递归遍历目录结构并从我编写的备份脚本中复制文件的示例。

          sub copy_directory {
          my ($source, $dest) = @_;
          my $start = time;
          
          # get the contents of the directory.
          opendir(D, $source);
          my @f = readdir(D);
          closedir(D);
          
          # recurse through the directory structure and copy files.
          foreach my $file (@f) {
              # Setup the full path to the source and dest files.
              my $filename = $source . "\\" . $file;
              my $destfile = $dest . "\\" . $file;
          
              # get the file info for the 2 files.
              my $sourceInfo = stat( $filename );
              my $destInfo = stat( $destfile );
          
              # make sure the destinatin directory exists.
              mkdir( $dest, 0777 );
          
              if ($file eq '.' || $file eq '..') {
              } elsif (-d $filename) { # if it's a directory then recurse into it.
                  #print "entering $filename\n";
                  copy_directory($filename, $destfile); 
              } else { 
                  # Only backup the file if it has been created/modified since the last backup 
                  if( (not -e $destfile) || ($sourceInfo->mtime > $destInfo->mtime ) ) {
                      #print $filename . " -> " . $destfile . "\n";
                      copy( $filename, $destfile ) or print "Error copying $filename: $!\n";
                  } 
              } 
          }
          
          print "$source copied in " . (time - $start) . " seconds.\n";       
          }
          

          【讨论】:

            【解决方案7】:

            与上述类似,但我认为最好的版本是(稍作修改)来自“perldoc -f readdir”:

            opendir(DIR, $somedir) || die "can't opendir $somedir: $!";
            @dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
            closedir DIR;
            

            【讨论】:

              【解决方案8】:

              来自:http://perlmeme.org/faqs/file_io/directory_listing.html

              #!/usr/bin/perl
              use strict;
              use warnings;
              
              my $directory = '/tmp';
              
              opendir (DIR, $directory) or die $!;
              
              while (my $file = readdir(DIR)) {
                  next if ($file =~ m/^\./);
                  print "$file\n";
              }
              

              以下示例(基于 perldoc -f readdir 中的代码示例)从打开的目录中获取以句点开头的所有文件(不是目录)。文件名在数组@dots 中找到。

              #!/usr/bin/perl
              
              use strict;
              use warnings;
              
              my $dir = '/tmp';
              
              opendir(DIR, $dir) or die $!;
              
              my @dots 
                  = grep { 
                      /^\./             # Begins with a period
                  && -f "$dir/$_"   # and is a file
              } readdir(DIR);
              
              # Loop through the array printing out the filenames
              foreach my $file (@dots) {
                  print "$file\n";
              }
              
              closedir(DIR);
              exit 0;
              
              
              closedir(DIR);
              exit 0;
              

              【讨论】:

                【解决方案9】:

                您还可以使用流行的Path::Tiny 模块中的children 方法:

                use Path::Tiny;
                my @files = path("/path/to/dir")->children;
                

                这将创建一个 Path::Tiny 对象数组,如果您想对文件执行操作,这些对象通常比文件名更有用,但如果您只需要名称:

                my @files = map { $_->stringify } path("/path/to/dir")->children;
                

                【讨论】:

                • 没有什么比一个 12 岁的问题的答案,而是通过跟踪一连串重复找到的,所以似乎是一个相当权威的 q 添加答案。
                猜你喜欢
                • 1970-01-01
                • 2011-04-08
                • 1970-01-01
                • 2018-03-07
                • 1970-01-01
                • 2015-12-13
                • 2019-09-23
                • 1970-01-01
                • 2014-08-08
                相关资源
                最近更新 更多