2016-04-24 127 views
1

我想從給定目錄中獲取所有文件和目錄,但我無法指定什麼類型(文件/目錄)。沒有什麼正在打印。我做錯了什麼以及如何解決它。以下是代碼:給定目錄的打印文件和子目錄

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); 
} 

回答

5

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

謝謝您給出的解決方案。第一個解決了我的問題:) –

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

這並不能真正解決OP的問題 – Borodin

+1

我認爲我們應該首先使用CPAN模塊,而不是編寫自己的代碼,因爲它已經被優化,並且能夠解決問題。 – AbhiNickz

+0

這幾乎不相關。你可能會認爲OP應該使用Python來代替,但是這並不能使Python解決方案變得有用。你還沒有幫助OP理解自己的代碼有什麼問題,並且當需要非遞歸解決方案時,解決方案會遞歸。你的輸出甚至不像原始代碼產生的東西,你的答案中有一個未使用的數組和一些雜亂的註釋部分。這是一個糟糕的解決方案 – Borodin

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文件,等等......這樣的「文件」通常可以作爲普通文件打開和閱讀,因此,某些事件而不是-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真的值得安裝。

相關問題