打印给定目录的文件和子目录

时间:2016-04-24 12:17:44

标签: perl file subdirectory readdir

我正在尝试从给定目录中获取所有文件和目录,但我无法指定类型(文件/目录)。什么都没打印出来。我做错了什么以及如何解决它。这是代码:

rows

3 个答案:

答案 0 :(得分:5)

readdir仅返回没有任何路径信息的节点名称。如果没有指定路径,文件测试操作员将查看当前工作目录,并且因为当前目录不是$currNode->rootDirectory,所以不会找到它们

我建议您使用File::Spec::Functions核心模块中的rel2abs将节点名称与路径相结合。您可以使用字符串连接,但库函数会处理极端情况,例如目录是否以斜杠结尾

值得指出的是,Perl标识符通常位于snake_case,熟悉该语言的人会感谢您不使用大写字母。对于标识符的第一个字符,尤其应该避免使用它们,因为这样的名称是为包名称

之类的全局字符保留的

我认为你的子程序看起来应该是这样的

use File::Spec::Functions 'rel2abs';

sub do_search {
    my ($curr_node) = @_;
    my $dir         = $curr_node->rootDirectory;

    opendir my $dh, $dir or die qq{Unable to open directory "$dir": $!};

    while ( my $node = readdir $dh ) {
        next if $node eq '.' or $node eq '..';

        my $fullname = rel2abs($node, $dir);

        print "File:     $node\n" if -f $fullname;
        print "Directory $node\n" if -d $fullname;
   }
}

另一种方法是将当前工作目录设置为正在读取的目录。这样就不需要操作文件路径,但是你需要在更改之前和之后保存和恢复原始工作目录

Cwd核心模块提供getcwd,您的代码看起来像这样

use Cwd 'getcwd';

sub do_search {
    my ($curr_node) = @_;

    my $cwd = getcwd;
    chdir $curr_node->rootDirectory or die $!;

    opendir my $dh, '.' or die $!;

    while ( my $node = readdir $dh ) {
        next if $node eq '.' or $node eq '..';

        print "File: \n" if -f $node;
        print "Directory $node\n" if -d $node;
   }

   chdir $cwd or die $!;
}

答案 1 :(得分:1)

使用此CPAN模块递归获取所有文件和子目录。

    use File::Find;        

    find(\&getFile, $dir);
    my @fileList;

    sub getFile{
        print $File::Find::name."\n";
        # Below lines will print only file name. 
        #if ($File::Find::name =~ /.*\/(.*)/ && $1 =~ /\./){
            #push @fileList, $File::Find::name."\n";
        }

答案 2 :(得分:1)

已经回答了,但有时候很方便不关心实现细节,你可以使用一些CPAN模块来隐藏这些细节。

其中一个是精彩的Path::Tiny模块。

您的代码可以是:

use 5.014;         #strict + feature 'say' + ...
use warnings;
use Path::Tiny;

do_search($_) for @ARGV;

sub do_search {
        my $curr_node = path(shift);
        for my $node ($curr_node->children) {
                say "Directory  : $node" if -d $node;
                say "Plain File : $node" if -f $node;
        }
}

children方法会自动排除...

您还需要了解-f测试仅适用于真实的files。因此,上面的代码排除了例如symlinks(其指向真实文件)或FIFO文件等等......这样的“文件”通常可以打开并作为普通文件读取,因此somethimes代替-f可以方便地使用-e && ! -d测试(例如存在,但不是目录)。

Path::Tiny有一些方法,例如你可以写

        for my $node ($curr_node->children) {
                print "Directory  : $node\n" if $node->is_dir;
                print "File       : $node\n" if $node->is_file;
        }

is_file方法通常是DWIM - 例如做:-e && ! -d

使用Path::Tiny您还可以使用iterator方法轻松扩展您的函数以遍历整个树:

use 5.014;
use warnings;
use Path::Tiny;

do_search($_) for @ARGV;

sub do_search {

    #maybe you need some error-checking here for the existence of the argument or like...

    my $iterator = path(shift)->iterator({recurse => 1});
    while( my $node = $iterator->() ) {
        say "Directory  : ", $node->absolute if $node->is_dir;
        say "File       : ", $node->absolute if $node->is_file;
    }
}

上面打印了从给定参数递归下来的所有文件和目录的类型......

等等...... Path::Tiny真的值得安装。