打开/处理目录中所有文件的最有效方法是什么?

时间:2011-06-12 20:59:02

标签: perl

我需要对目录的所有文件执行我的脚本(搜索)。以下是有效的方法。我只是问哪个是最好的。 (我需要表单的文件名:parsedchpt31_4.txt)

水珠:

my $parse_corpus; #(for all options)
##glob (only if all files in same directory as script?):
my @files = glob("parsed"."*.txt");
foreach my $file (@files) {
    open($parse_corpus, '<', "$file") or die $!;
     ... all my code...
}

readdir with while和conditions:

##readdir:
my $dir = '.';
opendir(DIR, $dir) or die $!;

while (my $file = readdir(DIR)) {
    next unless (-f "$dir/$file"); ##Ensure it's a file
    next unless ($file =~ m/^parsed.*\.txt/); ##Ensure it's a parsed file
    open($parse_corpus, '<', "$file") or die "Couldn't open directory $!";
     ... all my code...
}

readdir with foreach and grep:

##readdir+grep:
my $dir = '.';
    opendir(DIR, $dir) or die $!;    
foreach my $file (grep {/^parsed.*\.txt/} readdir (DIR)) {
    next unless (-f "$dir/$file"); ##Ensure it's a file
    open($parse_corpus, '<', "$file") or die "Couldn't open directory $!";
    ... all my code...
}

文件::查找:

##File::Find
my $dir = "."; ##current directory: could be (include quotes): '/Users/jon/Desktop/...'
my @files;
find(\&open_file, $dir); ##built in function
sub open_file {
    push @files, $File::Find::name if(/^parsed.*\.txt/);
}
foreach my $file (@files) {
    open($parse_corpus, '<', "$file") or die $!;
     ...all my code...
} 

还有其他方法吗?将我的整个脚本包含在循环中是否合适?可以,我不使用closedir吗?我把它传递给其他人,我不确定他们的文件在哪里(可能无法使用glob)

非常感谢,希望这是一个正确的问题。

3 个答案:

答案 0 :(得分:4)

最佳或最有效的方法取决于您的目的和更大的背景。在原始速度,代码简单性或其他方面,你的意思是最好的吗?我怀疑内存考虑应该推动这种选择。目录中有多少个文件?

纯粹的实用性,glob方法运作良好。在诉诸任何涉及的问题之前,我会问是否存在问题。

如果你能够使用其他模块,另一种方法是让别人担心肮脏的细节:

use File::Util qw();
my $fu = File::Util->new;
my @files = $fu->list_dir($dir, qw(--with-paths --files-only));

请注意File::Find执行递归搜索,降序到所有子目录。很多时候你不想要或不需要它。

我还要补充一点,我不喜欢你的两个readdir例子,因为它们混合了不同的功能:(1)获取文件名,(2)处理单个文件。我会将这些工作分开。

my $dir = '.';
opendir(my $dh, $dir) or die $!; # Use a lexical directory handle.
my @files = 
    grep { -f }
    map  { "$dir/$_" }
    grep { /^parsed.*\.txt$/ }
    readdir($dh);

for my $file (@files){
    ...
}

答案 1 :(得分:1)

我认为使用while循环是更安全的答案。为什么?因为将所有文件名加载到数组中可能意味着大量使用内存,并且使用逐行操作可以避免此问题。

我更喜欢readdirglob,但这可能更多的是品味问题。

如果性能存在问题,可以说对于-f扩展名的任何文件都不需要进行.txt检查。

答案 2 :(得分:1)

我发现使用完美合作伙伴opendir / readdirFile::chdir(我最喜欢的CPAN模块,非常适合跨平台)的递归目录行走功能可以让人轻松清晰如果需要,可以操作包含子目录的目录中的任何内容(如果没有,省略递归)。

示例(一个简单的深ls):

#!/usr/bin/env perl
use strict;
use warnings;

use File::chdir; #Provides special variable $CWD
# assign $CWD sets working directory
# can be local to a block
# evaluates/stringifies to absolute path
# other great features

walk_dir(shift);

sub do_something {
  print shift . "\n";
}

sub walk_dir {
  my $dir = shift;
  local $CWD = $dir;
  opendir my $dh, $CWD; # lexical opendir, so no closedir needed
  print "In: $CWD\n";

  while (my $entry = readdir $dh) {
    next if ($entry =~ /^\.+$/);
    # other exclusion tests    

    if (-d $entry) {
      walk_dir($entry);
    } elsif (-f $entry) {
      do_something($entry);
    }
  }

}