この質問は これ からのスピンオフです。いくつかの歴史:私が最初にPerlを学んだとき、私はそれがより簡単だと思ったので、ほとんどいつもglob
+ opendir
ではなくreaddir
を使用しました。その後、さまざまな投稿や読み物でglob
が悪いことが示唆されたため、今ではほとんどの場合readdir
を使用しています。
考えた後 この最近の質問 私はどちらか一方の選択の理由が二の次かもしれないことに気づきました。それで、私はいくつかの賛否両論をレイアウトするつもりです、そして私はより経験豊富なPerlの人々がチャイムを鳴らして明確にすることができることを望んでいます。一言で言えば、glob
よりもreaddir
またはreaddir
よりもglob
を好む説得力のある理由がありますか(一部またはすべての場合)?
glob
長所:glob
対readdir
はコンテストではありません)(ysthの回答から;以下のglob
cons 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
を無用に使用します)。(ブライアンの回答から)存在しないファイル名を返すことができます:
$ Perl -le 'print glob "{ab}{cd}"'
readdir
長所:opendir
は、プログラムで渡す(そして再利用する)ことができるファイルハンドルを返しますが、glob
は単にリストを返しますreaddir
は適切なイテレータであり、rewinddir
、seekdir
、telldir
に関数を提供します。glob
の機能のいくつかに基づく純粋な推測。とにかくこのレベルの最適化についてはあまり心配していませんが、理論的なプロです。)glob
よりもエッジケースのバグが発生しにくいですか?0
という名前を付けないように説得する場合があります(欠点もあります-ブラッドの回答を参照してください)readdir
短所:.
および..
アイテムをgrep
アウトすることを覚えていない場合は、アイテムを数えるときにwillビットを取得します、またはファイルツリーを再帰的に下って歩いてみてください。readdir
は大文字と小文字を区別せずに、アルファベット順にアイテムを返します。 DebianボックスとOpenBSDサーバーでは、順序は完全にランダムです。私はMacをAppleの組み込みPerl(5.8.8)と自分でコンパイルした5.10.1でテストしました。 Adobeボックスは、OpenBSDマシンと同様に5.10.0です。これはPerlではなくファイルシステムの問題なのだろうか?0
という名前のファイルを必ずしもうまく処理できるとは限りません(プロも参照してください-ブラッドの回答を参照してください)それらの間の最も重要で最大の違いを見逃しました。glob
はリストを返しますが、opendir
はディレクトリハンドルを提供します。そのディレクトリハンドルを渡して、他のオブジェクトやサブルーチンに使用させることができます。ディレクトリハンドルを使用すると、サブルーチンまたはオブジェクトは、それがどこから来たのか、他に誰がそれを使用しているのかなどについて何も知る必要がありません。
sub use_any_dir_handle {
my( $dh ) = @_;
rewinddir $dh;
...do some filtering...
return \@files;
}
Dirhandleを使用すると、seekdir
を使用して移動できる制御可能なイテレータがありますが、glob
を使用すると次のアイテムを取得するだけです。
ただし、他の場合と同様に、コストとメリットは、特定のコンテキストに適用した場合にのみ意味があります。それらは特定の用途以外には存在しません。あなたはそれらの違いの優れたリストを持っていますが、私はあなたがそれらで何をしようとしているのかを知らずにそれらの違いを分類しません。
覚えておくべき他のいくつかのこと:
opendir
を使用して独自のグロブを実装できますが、その逆はできません。
globは独自のワイルドカード構文を使用し、それだけで取得できます。
globは、存在しないファイル名を返すことができます。
$ Perl -le 'print glob "{ab}{cd}"'
glob pros:存在しない「ファイル名」を返すことができます:
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♦
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";
コードが同じ番号を2回出力すると予想されますが、0
という名前のファイルがあるために出力されません。私のコンピューターでは、Perlv5.10.0およびv5.10.1でテストされた251
および188
が出力されます。
この問題により、ファイル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に組み込まれたパッチを送信したので、Perlv5.12.0がリリースされたときに正しく機能します。
私の修正はこれを変換します:
while( readdir $dir ){ ... }
これに:
while( defined( $_ = readdir $dir ){ ...}
これにより、read
がファイルに対して機能したのと同じように機能します。実際には同じコードですが、対応するif
ステートメントに別の要素を追加しただけです。
glob
を使用すると、glob "*/*/*"
のように、特定の固定深度のすべてのサブディレクトリを簡単に読み取ることができます。私はこれを何度か便利だと思っています。
まあ、あなたはほとんどそれをカバーしています。これらすべてを考慮に入れると、簡単な1回限りのスクリプトをまとめるときに、glob
を使用する傾向があり、その動作は私が望むものであり、opendir
とreaddir
進行中の本番コードまたはライブラリでは、時間をかけてより明確でクリーンなコードが役立ちます。
小さくて単純なものについては、私はglob
を好みます。つい先日、私はそれと20行のPerlスクリプトを使用して、音楽ライブラリの大部分にタグを付け直しました。ただし、glob
の名前はかなり奇妙です。グロブ?名前に関する限り、それはまったく直感的ではありません。
readdir
との私の最大の問題は、ほとんどの人にとってやや奇妙な方法でディレクトリを処理することです。通常、プログラマーはディレクトリをストリームとは考えず、globが提供するリソースまたはリストと見なします。名前はより良く、機能はより良いですが、インターフェースはまだ何かが望まれています。
それはかなり包括的なリストでした。 readdir
(およびreaddir
+ grep
)はglob
よりもオーバーヘッドが少ないため、分析する必要がある場合はreaddir
にとってプラスになります。たくさんのディレクトリ。
グロブの長所:
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("*");
同様に、File::Slurp
にはread_dir
という関数があります。
スクリプトではFile::Slurp
の他の関数を頻繁に使用するため、read_dir
も習慣になっています。
また、次のオプションもあります:err_mode
、prefix
、およびkeep_dot_dot
。
まず、いくつかの読書をします。 9.6章。 of Perl Cookbook は、ディスカッションの見出しのすぐ下に、私がうまく行きたいポイントの概要を示しています。
次に、Perlディレクトリでglob
とdosglob
を検索します。さまざまなソース(ファイルリストを取得する方法)を使用できますが、dosglob
を指定する理由は、Windowsプラットフォームを使用している場合(およびdosglob
を使用している場合)です。解決策)、実際にはopendir
/readdir
/closedir
を使用しています。他のバージョンでは、組み込みのシェルコマンドまたはプリコンパイルされたOS固有の実行可能ファイルを使用します。
特定のプラットフォームをターゲットにしていることがわかっている場合は、この情報を活用できます。参考までに、Strawberry Perl Portableエディション5.12.2でこれを調べたので、Perlの新しいバージョンと元のバージョンでは状況が少し異なる場合があります。