Какие причины предпочитают glob над readdir (или наоборот) в Perl?
этот вопрос является ответвлением от этот. Немного истории: когда я впервые узнал Perl, я почти всегда использовал glob
, а не opendir
+ readdir
потому что мне было легче. Затем позже различные сообщения и чтения предположили, что glob
было плохо, и поэтому теперь я почти всегда использую readdir
.
поразмыслив этот последний вопрос я понял, что мои причины для того или иного выбора могут быть чушью. Итак, я собираюсь выложить некоторые плюсы и минусы, и я надеюсь, что более опытные люди Perl могут вмешаться и уточнить. Вопрос в двух словах: есть ли веские причины предпочесть glob
to readdir
или readdir
до glob
(в некоторых или во всех случаях)?
glob
плюсы:
- нет dotfiles (если вы попросите)
- заказ деталей гарантирован
- нет необходимости добавлять имя каталога на элементы вручную
- лучшее имя (давай -
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
плюсы:
- старые версии просто сломаны (но "старше" означает pre 5.6, я думаю, и, честно говоря, если вы используете pre 5.6 Perl, у вас есть большие проблемы)
- звонки
stat
каждый раз (т. е. бесполезное использованиеstat
in большинство случаев.) - проблемы с пробелами в именах каталогов (это все еще верно?)
-
(из ответа Брайана) может возвращать имена файлов, которые не существуют:
$ perl -le 'print glob "{ab}{cd}"'
readdir
плюсы:
- (из ответа Брайана)
opendir
возвращает файловую ручку, которую вы можете передать в своей программе (и повторно использовать), ноglob
просто возвращает список - (из ответа Брайана)
readdir
является правильным итератором и предоставляет функции дляrewinddir
,seekdir
,telldir
- быстрее? (Чистая догадка, основанная на некоторых
glob
' s особенности сверху. Я не очень беспокоюсь об этом уровне оптимизации, но это теоретический профессионал.) - менее склонны к краевым ошибкам, чем
glob
? - читает все (dotfiles тоже) по умолчанию (это также con)
- может убедить вас не называть файл
0
(афера Также-см. Брэда ответ) - кого? Бюллер? Бюллер?
readdir
плюсы:
- если вы не помните, чтобы добавить имя каталога, вы будет получить бит при попытке сделать filetests или копировать элементы или редактировать элементы или...
- если вы не помните к
grep
на.
и..
предметы, вы будет получить бит при подсчете элементов, или попытаться ходить рекурсивно вниз по дереву файлов или... - сделал Я упоминал о добавлении имени каталога? (Sidenote, но мой самый первый пост в списке новичков Perl был классическим: "почему этот код с использованием filetests не работает некоторое время?- проблема, связанная с этим, попалась. Видимо, мне все еще горько.)
- элементы возвращаются в произвольном порядке. Это означает, что вам часто придется помнить, чтобы отсортировать их каким-то образом. (Это может быть профи, если это означает большую скорость, и если это означает, что вы на самом деле думаю о том, как и если вам нужно отсортировать элементы.) редактировать: ужасно маленький образец, но на Mac
readdir
возвращает элементы в алфавитном порядке, без учета регистра. На коробке Debian и сервере OpenBSD порядок совершенно случайный. Я протестировал Mac со встроенным Perl от Apple (5.8.8) и моим собственным скомпилированным 5.10.1. Коробка Debian-5.10.0, как и машина OpenBSD. Интересно, это проблема файловой системы, а не Perl? - читает все (dotfiles тоже) по умолчанию (это также Pro)
- не обязательно хорошо справляется с файлом с именем
0
(см. также плюсы-см. ответ Брэда)
10 ответов
вы пропустили самую важную, самую большую разницу между ними: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";
вы ожидаете, что код будет печатать один и тот же номер дважды, но это не так, потому что есть файл с именем 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
заявления.
glob
позволяет удобно читать все подкаталоги заданной фиксированной глубины, как в glob "*/*/*"
. Я нашел это удобным в нескольких случаях.
Ну, вы в значительной степени покрыть его. Все это учитывается, я склонен использовать glob
когда я бросаю вместе быстрый одноразовый скрипт и его поведение-это именно то, что я хочу, и использовать opendir
и readdir
в текущем производственном коде или библиотеках, где я могу занять свое время и яснее, более чистый код полезен.
для небольших, простых вещей, я предпочитаю glob
. Как раз на днях я использовал его и двадцатистрочный скрипт perl, чтобы переписать большую часть моей музыкальной библиотеки. glob
, однако, имеет довольно странное название. Глоб? Это совсем не интуитивно, если говорить о названии.
мое самое большое зависание с readdir
это то, что он обрабатывает каталог таким образом, что это несколько странно для большинства людей. Обычно программисты не думают о каталоге как о потоке, они думают о нем как о ресурсе или списке, Глоб, который обеспечивает. Название лучше, функциональность лучше, но интерфейс все равно оставляет желать лучшего.
Это был довольно полный список. 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
is: вы должны предоставить полный путь к каталогу, чтобы получить полные пути назад. Документы Perl, похоже, не упоминают об этом, и ни один из сообщений здесь.
что это значит glob
может использоваться вместо readdir
когда вы хотите просто имена файлов (а не полные пути), и вы не хотите возвращать скрытые файлы, т. е. те, которые начинаются с '.'. Например,
chdir ("../..");
say for glob("*");
на подобной ноте, File::Slurp
имеет функцию read_dir
.
С File::Slurp
другие функции много в моих скриптах,read_dir
стало привычкой.
он также имеет следующие параметры:err_mode
, prefix
и keep_dot_dot
.
во-первых, что-нибудь почитать. Глава 9.6. из Поваренная Книга Perl очерчивает точку, которую я хочу получить красиво, только под заголовком обсуждения.
во-вторых, выполните поиск glob
и dosglob
в вашем каталоге Perl. Хотя можно использовать много разных источников (способы получения списка файлов), причина, по которой я указываю вам на dosglob
это если вы находитесь на платформе Windows (и используете dosglob
решение), он использует opendir
/readdir
/closedir
. В других версиях используются встроенные команды оболочки или предварительно скомпилированные исполняемые файлы ОС.
если вы знаете, что вы ориентируетесь на конкретную платформу, вы можете использовать эту информацию в своих интересах. Просто для справки я посмотрел на это на Strawberry Perl Portable edition 5.12.2, поэтому все может немного отличаться на более новых или оригинальных версиях Perl.