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

问题描述:

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

sub DoSearch { 
    my $currNode = shift; 
    my $currentDir = opendir (my $dirHandler, $currNode->rootDirectory) or die $!; 

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

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

    closedir($dirHandler); 
} 

readdir仅返回没有任何路径信息的节点名称。该文件的测试运营商将看在当前工作目录,如果没有指定路径,因为当前目录是不是$currNode->rootDirectory他们不会被人发现

我建议你使用rel2absFile::Spec::Functions核心模块的节点相结合名称与路径。您可以使用字符串连接,但库函数处理角落情况,如目录是否以斜线结尾

还值得指出的是,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 $!; 
} 
恢复原来的工作目录
+0

谢谢您给出的解决方案。第一个解决了我的问题:) –

使用此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"; 
     } 
+0

这并不能真正解决OP的问题 – Borodin

+1

我认为我们应该首先使用CPAN模块,而不是编写自己的代码,因为它已经被优化,并且能够解决问题。 – AbhiNickz

+0

这几乎不相关。你可能会认为OP应该使用Python来代替,但是这并不能使Python解决方案变得有用。你还没有帮助OP理解自己的代码有什么问题,并且当需要非递归解决方案时,解决方案会递归。你的输出甚至不像原始代码产生的东西,你的答案中有一个未使用的数组和一些杂乱的注释部分。这是一个糟糕的解决方案 – Borodin

已经回答了,但有时候不太在意实施细节,您可以使用一些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文件,等等......这样的“文件”通常可以作为普通文件打开和阅读,因此,某些事件而不是-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真的值得安装。