Tel*_*hus 62 perl glob readdir
这个问题是从这个问题中分拆出来的.一些历史:当我第一次学习Perl时,我总是使用glob而不是opendir+ readdir因为我发现它更容易.后来各种帖子和读物表明这glob很糟糕,所以现在我几乎总是使用readdir.
在思考了这个最近的问题之后,我意识到我选择其中一个或另一个选择的理由可能是无聊的.所以,我将列出一些优点和缺点,我希望更有经验的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}}";
Run Code Online (Sandbox Code Playgroud)glob 缺点:stat每次调用(即stat在大多数情况下无用).(来自brian的回答)可以返回不存在的文件名:
$ perl -le 'print glob "{ab}{cd}"'
Run Code Online (Sandbox Code Playgroud)readdir 优点:opendir返回一个文件句柄,你可以在你的程序中传递(并重用),但glob只返回一个列表readdir是正确的迭代器,并提供功能rewinddir,seekdir,telldirglob特征进行纯粹的猜测.无论如何,我并不是真的担心这种优化水平,但它是理论专家.)glob?0(con也 - 请参阅Brad的回答)readdir 缺点:grep出去,那么当你计算项目时,你会得到一点,或者尝试递归地沿文件树行走或者.........readdir上按字母顺序返回项目,不区分大小写.在Debian盒子和OpenBSD服务器上,订单是完全随机的.我用Apple的内置Perl(5.8.8)和我自己编译的5.10.1测试了Mac.Debian框是5.10.0,OpenBSD机器也是如此.我想知道这是文件系统问题,而不是Perl?0(参见专业人士 - 请参阅Brad的回答)bri*_*foy 43
你错过了它们之间最重要,最大的区别:glob给你一个列表,但opendir给你一个目录句柄.您可以传递该目录句柄,让其他对象或子例程使用它.使用目录句柄,子例程或对象不必知道它来自何处,还有谁在使用它,等等:
sub use_any_dir_handle {
my( $dh ) = @_;
rewinddir $dh;
...do some filtering...
return \@files;
}
Run Code Online (Sandbox Code Playgroud)
使用dirhandle,你有一个可控制的迭代器,你可以随身携带seekdir,虽然glob你只需要下一个项目.
与任何事情一样,成本和收益仅在应用于特定环境时才有意义.它们不存在于特定用途之外.你有一个很好的差异列表,但我不会在不知道你试图用它们做什么的情况下对这些差异进行分类.
其他一些要记住的事情:
你可以实现自己的glob opendir,但不是相反.
glob使用自己的通配符语法,这就是你得到的.
glob可以返回不存在的文件名:
$ perl -le 'print glob "{ab}{cd}"'
Run Code Online (Sandbox Code Playgroud)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?
Run Code Online (Sandbox Code Playgroud)
下面是一个缺点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";
Run Code Online (Sandbox Code Playgroud)
您可能希望代码两次打印相同的数字,但它不会,因为有一个名称为的文件0.在我的计算机上打印251,并188使用Perl v5.10.0和v5.10.1进行测试
这个问题也使得它只是打印出一堆空行,而不管文件是否存在0:
use 5.10.0;
opendir my $dir, '.';
say while readdir $dir;
Run Code Online (Sandbox Code Playgroud)
这在哪里总是很好:
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 '*';
Run Code Online (Sandbox Code Playgroud)
我解决了这些问题,并发送了一个补丁,使其成为Perl v5.11.2,因此当它出现时,这将适用于Perl v5.12.0.
我的修复转换了这个:
while( readdir $dir ){ ... }
Run Code Online (Sandbox Code Playgroud)
进入这个:
while( defined( $_ = readdir $dir ){ ...}
Run Code Online (Sandbox Code Playgroud)
这使得它的工作方式与read处理文件的方式相同.实际上它是相同的代码,我只是在相应的if语句中添加了另一个元素.
| 归档时间: |
|
| 查看次数: |
11500 次 |
| 最近记录: |