如何让 Perl 将给定目录的内容读入数组?
反引号可以做到这一点,但有没有使用“scandir”或类似术语的方法?
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";
}
EDIT2:大多数其他答案都是有效的,但我想特别评论这个答案,其中提供了这个解决方案:
opendir(DIR, $somedir) || die "Can't open directory $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;
首先,记录它在做的事情,因为海报没有:它通过一个grep()从readdir()传递返回的列表,该列表只返回那些是文件的值(而不是目录、设备、命名管道等)并且不以点开头(这会使列表名称产生误导,但这是由于他在从 readdir() 文档中复制它时所做的更改)。由于它限制了它返回的目录的内容,我认为它在技术上不是这个问题的正确答案,但它说明了一个用于在Perl中过滤文件名的常用习语,我认为记录下来很有价值。另一个经常看到的例子是:@dots
@list = grep !/^\.\.?$/, readdir(D);
此代码段从目录句柄 D 中读取所有内容,但'.'除外。和 '..',因为它们很少需要在列表中使用。
一个快速而肮脏的解决方案是使用glob
@files = glob ('/path/to/dir/*');
这将在一行中完成(注意末尾的“*”通配符)
@files = </path/to/directory/*>;
# To demonstrate:
print join(", ", @files);
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;
您可以使用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()
函数提供了一个替代的、更简洁的接口。
这是一个通过目录结构递归并从我编写的备份脚本中复制文件的示例。
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";
}
与上面类似,但我认为最好的版本是(稍作修改)来自“perldoc -f readdir”:
opendir(DIR, $somedir) || die "can't opendir $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;
来自: 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;
您还可以使用children
流行Path::Tiny
模块中的方法:
use Path::Tiny;
my @files = path("/path/to/dir")->children;
这将创建一个对象数组,Path::Tiny
如果您想对文件执行操作,这些对象通常比文件名更有用,但如果您只需要名称:
my @files = map { $_->stringify } path("/path/to/dir")->children;