Как мне прочитать содержимое каталога в Perl? - PullRequest
35 голосов
/ 22 августа 2008

Как мне заставить Perl читать содержимое данного каталога в массив?

Backticks может это сделать, но есть ли какой-нибудь метод, использующий 'scandir' или подобный термин?

Ответы [ 8 ]

51 голосов
/ 22 августа 2008
opendir(D, "/path/to/directory") || die "Can't open directory: $!\n";
while (my $f = readdir(D)) {
    print "\$f = $f\n";
}
closedir(D);

РЕДАКТИРОВАТЬ: Ой, извините, пропустил часть "в массив":

my $d = shift;

opendir(D, "$d") || die "Can't open directory $d: $!\n";
my @list = readdir(D);
closedir(D);

foreach my $f (@list) {
    print "\$f = $f\n";
}

РЕДАКТИРОВАТЬ2: Большинство других ответов действительны, но я хотел прокомментировать этот ответ специально, в котором предлагается это решение:

opendir(DIR, $somedir) || die "Can't open directory $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;

Во-первых, чтобы документировать то, что он делает, так как автор не сделал: он передает возвращенный список из readdir () через grep () , который возвращает только те значения, которые файлы (в отличие от каталогов, устройств, именованных каналов и т. д.), которые не начинаются с точки (что вводит в заблуждение имя списка @dots, но это из-за изменений, которые он сделал при копировании его из readdir ( ) документация). Поскольку он ограничивает содержимое каталога, который он возвращает, я не думаю, что это технически правильный ответ на этот вопрос, но он иллюстрирует общую идиому, используемую для фильтрации имен файлов в Perl , и я подумал, что это будет ценный документ. Другой пример, который часто видели:

@list = grep !/^\.\.?$/, readdir(D);

Этот фрагмент читает все содержимое из дескриптора каталога D , кроме '.' и '..', поскольку их очень редко желательно использовать в списке.

13 голосов
/ 22 августа 2008

Быстрое и грязное решение заключается в использовании glob

@files = glob ('/path/to/dir/*');
8 голосов
/ 22 августа 2008

IO :: Dir хорош и предоставляет также интерфейс с привязанным хешем.

Из perldoc:

use IO::Dir;
$d = IO::Dir->new(".");
if (defined $d) {
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

tie %dir, 'IO::Dir', ".";
foreach (keys %dir) {
    print $_, " " , $dir{$_}->size,"\n";
}

Так что вы можете сделать что-то вроде:

tie %dir, 'IO::Dir', $directory_name;
my @dirs = keys %dir;
7 голосов
/ 22 августа 2008

Это будет сделано в одну строку (обратите внимание на подстановочный знак '*' в конце)

@files = </path/to/directory/*>;
# To demonstrate:
print join(", ", @files);
5 голосов
/ 01 сентября 2008

Вы можете использовать DirHandle :

use DirHandle;
$d = new DirHandle ".";
if (defined $d)
{
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

DirHandle предоставляет альтернативный, более чистый интерфейс для функций opendir(), closedir(), readdir() и rewinddir().

1 голос
/ 23 августа 2008

Аналогично приведенному выше, но я думаю, что лучшая версия (слегка измененная) из "perldoc -f readdir":

opendir(DIR, $somedir) || die "can't opendir $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;
1 голос
/ 22 августа 2008

Вот пример рекурсивного просмотра структуры каталогов и копирования файлов из сценария резервного копирования, который я написал.

sub copy_directory {
my ($source, $dest) = @_;
my $start = time;

# get the contents of the directory.
opendir(D, $source);
my @f = readdir(D);
closedir(D);

# recurse through the directory structure and copy files.
foreach my $file (@f) {
    # Setup the full path to the source and dest files.
    my $filename = $source . "\\" . $file;
    my $destfile = $dest . "\\" . $file;

    # get the file info for the 2 files.
    my $sourceInfo = stat( $filename );
    my $destInfo = stat( $destfile );

    # make sure the destinatin directory exists.
    mkdir( $dest, 0777 );

    if ($file eq '.' || $file eq '..') {
    } elsif (-d $filename) { # if it's a directory then recurse into it.
        #print "entering $filename\n";
        copy_directory($filename, $destfile); 
    } else { 
        # Only backup the file if it has been created/modified since the last backup 
        if( (not -e $destfile) || ($sourceInfo->mtime > $destInfo->mtime ) ) {
            #print $filename . " -> " . $destfile . "\n";
            copy( $filename, $destfile ) or print "Error copying $filename: $!\n";
        } 
    } 
}

print "$source copied in " . (time - $start) . " seconds.\n";       
}
0 голосов
/ 20 февраля 2017

от: http://perlmeme.org/faqs/file_io/directory_listing.html

#!/usr/bin/perl
use strict;
use warnings;

my $directory = '/tmp';

opendir (DIR, $directory) or die $!;

while (my $file = readdir(DIR)) {
    next if ($file =~ m/^\./);
    print "$file\n";
}

В следующем примере (на основе примера кода из perldoc -f readdir) все файлы (не каталоги) получают начиная с точки из открытого каталога. Имена файлов находятся в массиве @ dots.

#!/usr/bin/perl

use strict;
use warnings;

my $dir = '/tmp';

opendir(DIR, $dir) or die $!;

my @dots 
    = grep { 
        /^\./             # Begins with a period
    && -f "$dir/$_"   # and is a file
} readdir(DIR);

# Loop through the array printing out the filenames
foreach my $file (@dots) {
    print "$file\n";
}

closedir(DIR);
exit 0;


closedir(DIR);
exit 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...