这个问题是this one的衍生产品。一些历史:当我第一次学习Perl时,我几乎总是使用glob
而不是opendir
+ readdir
因为我发现它更容易。后来各种帖子和阅读材料都表明glob
很糟糕,所以现在我几乎总是使用readdir
。
在思考this recent question之后,我意识到我选择其中一个或另一个选择的原因可能是无聊的。所以,我将列出一些优点和缺点,我希望更有经验的Perl人可以插入并澄清。简而言之,问题是否有令人信服的理由选择glob
到readdir
或readdir
到glob
(在某些或所有情况下)?
glob
专业人士:glob
与readdir
不是竞争,如果我们只是通过名字判断的话)(来自ysth的回答;参见下面的glob
缺点4)可以返回不存在的文件名:
@deck = glob "{A,K,Q,J,10,9,8,7,6,5,4,3,2}{\x{2660},\x{2665},\x{2666},\x{2663}}";
glob
缺点:stat
(例如,在大多数情况下无用stat
)。(来自brian的回答)可以返回不存在的文件名:
$ perl -le 'print glob "{ab}{cd}"'
readdir
专业人士:opendir
返回一个文件句柄,您可以在程序中传递(并重复使用),但glob
只返回一个列表readdir
是一个正确的迭代器,并为rewinddir
,seekdir
,telldir
提供函数glob
的一些特征进行纯粹的猜测。无论如何,我并不是真的担心这种优化水平,但它是理论专家。)glob
0
(也是骗子 - 见Brad的回答)readdir
缺点:grep
.
和..
项,{strong>将在您计算物品或尝试行走时获取位以递归方式向下移动文件树或... readdir
按字母顺序返回项目,不区分大小写。在Debian盒子和OpenBSD服务器上,订单是完全随机的。我用Apple的内置Perl(5.8.8)和我自己编译的5.10.1测试了Mac。 Debian框是5.10.0,OpenBSD机器也是如此。我想知道这是文件系统问题,而不是Perl? 0
的文件(参见专业人士 - 请参阅Brad的回答)答案 0 :(得分:43)
您错过了它们之间最重要,最大的区别:glob
会返回一个列表,但opendir
会为您提供目录句柄。您可以传递该目录句柄,让其他对象或子例程使用它。使用目录句柄,子例程或对象不必知道它来自何处,还有谁在使用它,等等:
sub use_any_dir_handle {
my( $dh ) = @_;
rewinddir $dh;
...do some filtering...
return \@files;
}
使用dirhandle,你有一个可控制的迭代器,你可以使用seekdir
移动,虽然使用glob
你只需要下一个项目。
与任何事情一样,成本和收益仅在适用于特定情境时才有意义。它们不存在于特定用途之外。你有一个很好的差异列表,但我不会在不知道你试图用它们做什么的情况下对这些差异进行分类。
要记住的其他一些事情:
您可以使用opendir
实现自己的glob,但不是相反。
glob使用自己的通配符语法,这就是你得到的。
glob可以返回不存在的文件名:
$ perl -le 'print glob "{ab}{cd}"'
答案 1 :(得分:8)
glob pros:可以返回不存在的'filenames':
my @deck = List::Util::shuffle glob "{A,K,Q,J,10,9,8,7,6,5,4,3,2}{\x{2660},\x{2665},\x{2666},\x{2663}}";
while (my @hand = splice @deck,0,13) {
say join ",", @hand;
}
__END__
6♥,8♠,7♠,Q♠,K♣,Q♦,A♣,3♦,6♦,5♥,10♣,Q♣,2♠
2♥,2♣,K♥,A♥,8♦,6♠,8♣,10♠,10♥,5♣,3♥,Q♥,K♦
5♠,5♦,J♣,J♥,J♦,9♠,2♦,8♥,9♣,4♥,10♦,6♣,3♠
3♣,A♦,K♠,4♦,7♣,4♣,A♠,4♠,7♥,J♠,9♥,7♦,9♦
答案 2 :(得分:6)
这是opendir
和readdir
的缺点。
{
open my $file, '>', 0;
print {$file} 'Breaks while( readdir ){ ... }'
}
opendir my $dir, '.';
my $a = 0;
++$a for readdir $dir;
print $a, "\n";
rewinddir $dir;
my $b = 0;
++$b while readdir $dir;
print $b, "\n";
您可能希望代码两次打印相同的数字,但它不会,因为有一个名为0
的文件。在我的计算机上打印251
和188
,使用Perl v5.10.0和v5.10.1进行测试
这个问题也使得它只打印出一堆空行,而不管文件0
是否存在:
use 5.10.0;
opendir my $dir, '.';
say while readdir $dir;
这在哪里总能正常运作:
use 5.10.0;
my $a = 0;
++$a for glob '*';
say $a;
my $b = 0;
++$b while glob '*';
say $b;
say for glob '*';
say while glob '*';
我修复了这些问题,并发送了一个补丁程序,使其成为Perl v5.11.2,因此当它出现时,这将适用于Perl v5.12.0。
我的修正转换了这个:
while( readdir $dir ){ ... }
进入这个:
while( defined( $_ = readdir $dir ){ ...}
这使得它的工作方式与read
处理文件的方式相同。实际上它是相同的代码,我只是在相应的if
语句中添加了另一个元素。
答案 3 :(得分:5)
glob
可以方便地读取给定固定深度的所有子目录,如glob "*/*/*"
中所示。我在几个场合都发现了这个方便。
答案 4 :(得分:4)
嗯,你几乎涵盖了它。考虑到所有这些,当我拼凑一个快速的一次性脚本并且它的行为正是我想要的时候,我倾向于使用glob
,并使用opendir
和readdir
在正在进行的生产代码或库中,我可以花时间和更清晰,更清晰的代码是有帮助的。
答案 5 :(得分:3)
对于小而简单的事情,我更喜欢glob
。就在前几天,我使用它和二十行perl脚本来重新占据我的音乐库的大部分。然而,glob
有一个非常奇怪的名字。通配?就名字而言,它根本不直观。
我对readdir
的最大挫折是它以一种对大多数人来说有点奇怪的方式处理目录。通常,程序员不会将目录视为流,而是将其视为glob提供的资源或列表。名称更好,功能更好,但界面仍然有待改进。
答案 6 :(得分:2)
这是一个非常全面的清单。 readdir
(和readdir
+ grep
)的开销低于glob
,因此如果您需要分析大量目录,那么这对readdir
来说是一个加号
答案 7 :(得分:2)
glob pros:
3)无需手动将目录名称添加到项目
例外:
say for glob "*";
--output:--
1perl.pl
2perl.pl
2perl.pl.bak
3perl.pl
3perl.pl.bak
4perl.pl
data.txt
data1.txt
data2.txt
data2.txt.out
据我所知,glob
的规则是:您必须提供目录的完整路径才能获得完整路径。 Perl文档似乎没有提到这一点,这里也没有任何帖子。
这意味着当您只需要文件名(而不是完整路径)时,可以使用glob
代替readdir
,并且您不希望返回隐藏文件,即以'开头的文件。 ”。例如,
chdir ("../..");
say for glob("*");
答案 8 :(得分:2)
在类似的说明中,File::Slurp
有一个名为read_dir
的函数。
由于我在脚本中使用了File::Slurp
的其他功能,read_dir
也成为一种习惯。
它还有以下选项:err_mode
,prefix
和keep_dot_dot
。
答案 9 :(得分:1)
首先,做一些阅读。第9.6章。 Perl Cookbook的内容概述了我想要很好地解决的问题,就在讨论标题下。
其次,在Perl目录中搜索glob
和dosglob
。虽然可以使用许多不同的来源(获取文件列表的方法),但我指向dosglob
的原因是,如果您碰巧在Windows平台上(并使用dosglob
解决方案) ,它实际上是使用opendir
/ readdir
/ closedir
。其他版本使用内置shell命令或预编译的OS特定可执行文件。
如果您知道自己正在定位特定平台,则可以使用此信息。仅供参考,我在Strawberry Perl Portable版本5.12.2上进行了调查,因此在新版本或原始版本的Perl上可能略有不同。