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

Perl 打开/处理目录中所有文件的最有效方法是什么?,perl,Perl,我需要对目录中的所有文件执行脚本(搜索)。以下是有效的方法。我只是问哪个最好。(我需要格式为:parsedchpt31_4.txt的文件名) 全球: my$parse_语料库#(适用于所有选项) ##glob(仅当所有文件与脚本位于同一目录中时?): my@files=glob(“已解析”。*.txt”); foreach my$文件(@files){ 打开($parse_corpus),我认为使用while循环是更安全的答案。为什么?因为将所有文件名加载到一个数组中可能意味着大量内存使用,而使

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

全球:

my$parse_语料库#(适用于所有选项)
##glob(仅当所有文件与脚本位于同一目录中时?):
my@files=glob(“已解析”。*.txt”);
foreach my$文件(@files){

打开($parse_corpus),我认为使用
while
循环是更安全的答案。为什么?因为将所有文件名加载到一个数组中可能意味着大量内存使用,而使用逐行操作可以避免这个问题

我更喜欢
readdir
而不是
glob
,但这可能更多的是口味问题


如果性能是一个问题,可以说
-f
检查对于任何扩展名为
.txt
的文件都是不必要的。

最佳或最有效的方法取决于您的目的和更大的上下文。您是指原始速度、代码的简单性或其他方面的最佳方法吗?我怀疑内存是否操作应驱动此选择。目录中有多少文件

为了纯粹的实用性,
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){
    ...
}

我发现,使用perfect partners
opendir
/和(我的fav CPAN模块,非常适合跨平台)的递归目录遍历函数可以方便、清晰地操作目录中的任何内容,包括子目录(如果不需要,则省略递归)

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


感谢您的回答,除非
grep
对while循环更好,否则
grep
还是
next?
grep
与数组一起使用,因此它不适用。
grep
foreach
都会将文件名加载到一个列表中,如果您有大量文件,这可能是一件坏事。我认为他对这个问题很谨慎e
-f
检查。并非所有操作系统都强制执行文件扩展名,这意味着在Unix/Linux/Mac系统上,目录很可能有
.txt
扩展名。@Barry是的,我知道。这就是为什么我说“可以说”。目录不大(大约100个文件匹配)。这是出于兴趣,因为我研究了所有不同的方法。但是没有找到文件::Util…文件::find是为代码/完整性的任何其他用户提供的。为什么它们混合在一起不好?可读性或功能性?for是否具有与while相同的效果(根据TLP的回答)@Jon Comingling之所以不好,是因为它违背了优秀软件设计的一个基本原则——模块化或关注点分离。如果你遵循这些原则,你的程序将更可读、更可维护、更可测试和更具适应性。很难在简短的评论中就这个主题做出公正的评价,但它非常重要。酷,h我还没有听说过这个模块。它似乎非常灵活!我的一个问题是,我现在必须将Perl脚本合并到CGI脚本中,当加载页面时,它非常慢,其中任何一个会更快吗?您的问题是CGI本身。每次请求页面时,都需要一个新的
Perl
实例。这个启动时间是主要的延迟。尝试FastCGI或Mod_perl部署或更新的Plack系统以避免巨大的开销。由于我的帖子回答了问题,我将保持它不变。我将在perl环境中运行一个脚本,每次评估后都不会退出。您将需要
连续性
模块(提供有状态服务器).
##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...
} 
use File::Util qw();
my $fu = File::Util->new;
my @files = $fu->list_dir($dir, qw(--with-paths --files-only));
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){
    ...
}
#!/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);
    }
  }

}