Program Tip

Perl에서 readdir보다 glob을 선호하는 이유는 무엇입니까 (또는 그 반대로)?

programtip 2020. 11. 28. 10:20
반응형

Perl에서 readdir보다 glob을 선호하는 이유는 무엇입니까 (또는 그 반대로)?


이 질문은이 질문에서 파생 된 입니다. 몇 가지 역사 : Perl을 처음 배웠을 때, 나는 그것이 더 쉽다는 것을 알았 기 때문에 + glob보다는 거의 항상 사용 했습니다. 그 후 나중에 다양한 게시물과 읽기에서 그것이 나쁘다는 것을 제안 했기 때문에 지금은 거의 항상 .opendirreaddirglobreaddir

이 최근의 질문을 생각한 후에 나는 하나 또는 다른 선택에 대한 나의 이유가 멍청 할 수 있음을 깨달았습니다. 그래서 저는 몇 가지 장단점을 설명 할 것이며, 더 경험이 많은 Perl 사람들이 차임하고 명확히 할 수 있기를 바랍니다. 간단히 말해서 IS의 문제는 선호하는가 돋보이는 이유가 globreaddirreaddirglob(일부 또는 모든 경우에)?

glob 장점 :

  1. 도트 파일 없음 (요청하지 않는 한)
  2. 항목의 순서가 보장됩니다
  3. 수동으로 항목 앞에 디렉터리 이름을 추가 할 필요가 없습니다.
  4. 더 나은 이름 (이봐- 이름만으로 판단한다면 glob대결 readdir이 아님)
  5. (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 단점 :

  1. 이전 버전은 그냥 깨졌습니다 (그러나 '이전 버전'은 5.6 이전을 의미하며 솔직히 5.6 이전 Perl을 사용하는 경우 더 큰 문제가 있습니다)
  2. stat매번 호출 합니다 (즉, stat대부분의 경우 쓸모없는 사용 ).
  3. 디렉토리 이름의 공백 문제 (여전히 사실입니까?)
  4. (brian의 답변에서) 존재하지 않는 파일 이름을 반환 할 수 있습니다.

    $ perl -le 'print glob "{ab}{cd}"'
    

readdir 장점 :

  1. (brian의 대답에서) opendir프로그램에서 전달할 수 있고 재사용 할 수있는 파일 핸들을 glob반환 하지만 단순히 목록을 반환합니다.
  2. (브라이언의 대답에서) readdir적절한 반복자이며하는 기능을 제공 rewinddir, seekdir,telldir
  3. 더 빨리? ( glob위의의 일부 기능을 기반으로 한 순수한 추측입니다 . 어쨌든이 수준의 최적화에 대해서는별로 걱정하지 않지만 이론적 인 전문가입니다.)
  4. 엣지 케이스 버그에 덜 취약합니다 glob.
  5. 기본적으로 모든 항목 (도트 파일도)을 읽습니다 (이것은 또한 단점입니다).
  6. 파일 이름을 지정하지 않도록 설득 할 수 있습니다 0(죄수-Brad의 답변 참조).
  7. 누군가? Bueller? Bueller?

readdir 단점 :

  1. 당신이 디렉토리 이름을 씁니다 기억하지 않는 경우, 당신은 것입니다 당신이 filetests을하려고 또는 항목이나 항목 편집 또는 복사 할 때 비트를 얻을 수 ...
  2. 당신이 기억하지 않는 경우 grep아웃 ...항목, 당신은 것입니다 당신이 항목을 계산하거나 파일 트리 또는 아래로 반복적으로 걸을 때 비트를 얻을 수 ...
  3. 디렉토리 이름 앞에 언급 했습니까? (하지만 Perl Beginners 메일 목록에 대한 첫 번째 게시물은 "왜 파일 테스트와 관련된이 코드가 때때로 작동하지 않습니까?"라는 고전적인 문제였습니다.이 문제와 관련된 문제입니다. 분명히 저는 여전히 씁쓸합니다.)
  4. 항목은 특별한 순서없이 반환됩니다. 즉, 어떤 방식 으로든 정렬해야하는 경우가 많습니다. (더 빠른 속도를 의미하고 항목을 정렬하는 방법과 필요 여부를 실제로 생각 하는 것을 의미한다면 전문가가 될 수 있습니다 .) 편집 : 끔찍하게 작은 샘플이지만 Mac readdir에서는 대소 문자를 구분하지 않고 알파벳 순서로 항목을 반환합니다. 데비안 박스와 OpenBSD 서버에서 순서는 완전히 무작위입니다. 필자는 Apple의 내장 Perl (5.8.8)과 자체 컴파일 된 5.10.1로 Mac을 테스트했습니다. 데비안 상자는 OpenBSD 시스템과 마찬가지로 5.10.0입니다. 이것이 Perl이 아닌 파일 시스템 문제인지 궁금합니다.
  5. 기본적으로 모든 것을 읽습니다 (도트 파일도) (이것은 또한 프로입니다).
  6. 이름이 지정된 파일을 반드시 잘 처리하지는 않습니다 0(프로도 참조-Brad의 답변 참조)

당신은 그들 사이의 가장 중요하고 가장 큰 차이점을 놓쳤습니다 : glob목록을 돌려 주지만 opendir디렉토리 핸들을 제공합니다. 해당 디렉토리 핸들을 전달하여 다른 객체 나 서브 루틴이 사용하도록 할 수 있습니다. 디렉토리 핸들을 사용하면 서브 루틴이나 객체는 그것이 어디서 왔는지, 누가 그것을 사용하고 있는지 등에 대해 알 필요가 없습니다.

 sub use_any_dir_handle {
      my( $dh ) = @_;
      rewinddir $dh;
      ...do some filtering...
      return \@files;
      }

dirhandle을 사용하면으로 이동할 수있는 제어 가능한 반복기가 seekdir있지만 glob다음 항목 만 가져옵니다.

하지만 비용과 이점은 특정 상황에 적용될 때만 의미가 있습니다. 특정 용도 외에는 존재하지 않습니다. 당신은 그들의 차이점에 대한 훌륭한 목록을 가지고 있지만 당신이 그들과 무엇을하려고했는지 모르고는 그 차이점을 분류하지 않을 것입니다.

기억해야 할 기타 사항 :

  • 을 사용하여 자체 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";

코드가 동일한 번호를 두 번 인쇄 할 것이라고 예상 할 수 있지만 이름이 0. 내 컴퓨터에서 인쇄 251되고 188, Perl v5.10.0 및 v5.10.1로 테스트되었습니다.

이 문제는 또한 file의 존재에 관계없이 빈 줄을 인쇄하도록 만듭니다 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 '*';

I fixed these issues, and sent in a patch which made it into Perl v5.11.2, so this will work properly with Perl v5.12.0 when it comes out.

My fix converts this:

while( readdir $dir ){ ... }

into this:

while( defined( $_ = readdir $dir ){ ...}

Which makes it work the same way that read has worked on files. Actually it is the same bit of code, I just added another element to the corresponding if statements.


glob makes it convenient to read all the subdirectories of a given fixed depth, as in glob "*/*/*". I've found this handy in several occasions.


Well, you pretty much cover it. All that taken into account, I would tend to use glob when I'm throwing together a quick one-off script and its behavior is just what I want, and use opendir and readdir in ongoing production code or libraries where I can take my time and clearer, cleaner code is helpful.


For small, simple things, I prefer glob. Just the other day, I used it and a twenty line perl script to retag a large portion of my music library. glob, however, has a pretty strange name. Glob? It's not intuitive at all, as far as a name goes.

My biggest hangup with readdir is that it treats a directory in a way that's somewhat odd to most people. Usually, programmers don't think of a directory as a stream, they think of it as a resource, or list, which glob provides. The name is better, the functionality is better, but the interface still leaves something to be desired.


That was a pretty comprehensive list. readdir (and readdir + grep) has less overhead than glob and so that is a plus for readdir if you need to analyze lots and lots of directories.


glob pros:

3) No need to prepend the directory name onto items manually

Exception:

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

As far as I can tell, the rule for glob is: you must provide a full path to the directory to get full paths back. The Perl docs do not seem to mention that, and neither do any of the posts here.

That means that glob can be used in place of readdir when you want just filenames (rather than full paths), and you don't want hidden files returned, i.e. ones starting with '.'. For example,

chdir ("../..");  
say for glob("*");

On a similar note, File::Slurp has a function called read_dir.

Since I use File::Slurp's other functions a lot in my scripts, read_dir has also become a habit.

It also has following options: err_mode, prefix, and keep_dot_dot.


First, do some reading. Chapter 9.6. of the Perl Cookbook outlines the point I want to get to nicely, just under the discussion heading.

Secondly, do a search for glob and dosglob in your Perl directory. While many different sources (ways to get the file list) can be used, the reason why I point you to dosglob is that if you happen to be on a Windows platform (and using the dosglob solution), it is actually using opendir/readdir/closedir. Other versions use built-in shell commands or precompiled OS specific executables.

If you know you are targetting a specific platform, you can use this information to your advantage. Just for reference I looked into this on Strawberry Perl Portable edition 5.12.2, so things may be slightly different on newer or original versions of Perl.

참고URL : https://stackoverflow.com/questions/1506801/what-reasons-are-there-to-prefer-glob-over-readdir-or-vice-versa-in-perl

반응형