2013-12-12 30 views
3

嗨,我想讀取目錄和子目錄而不知道目錄名稱。當前目錄是「D:/ Temp」。 'Temp'具有像'A1','A2'這樣的子目錄。再次'A1'具有像'B1','B2'的子目錄。再次'B1'具有像'C1','C2'的子目錄。 Perl腳本不知道這些目錄。所以它必須首先找到目錄,然後在'C1'中一次讀取一個文件,一旦所有文件都在'C1'中讀取,它應該改變爲'C2'。我試着用下面的代碼在這裏我不想讀取陣列(@文件)中的所有文件,但在一次需要一個文件。在數組@dir元素應該是休閒。如何在不知道perl目錄名的情況下讀取目錄和子目錄?

$dir[0] = "D:/Temp/A1/B1/C1" 
$dir[1] = "D:/Temp/A1/B1/C2" 
$dir[2] = "D:/Temp/A1/B2/C1" 

下面是我試過的代碼。

use strict; 
    use File::Find::Rule; 
    use Data::Dumper; 

    my $dir = "D:/Temp"; 
    my @dir = File::Find::Rule->directory->in($dir); 
    print Dumper (\@dir); 
    my $readDir = $dir[3]; 
    opendir (DIR, $readDir) || die "Error in opening dir $readDir\n"; 
    my @files = grep { !/^\.\.?$/ } readdir DIR; 
    print STDERR "files: @files \n\n"; 

    for my $fil (@files) { 
     open (F, "<$fil"); 
     read (F, my $data); 
     close (F); 
     print "$data"; 
    } 
+0

是否有「 d:/溫度/ A1/B2/C2" ? – Kenosis

+0

@Kenosis是的。 – ImDrPatil

+0

考慮在您的問題中添加**遞歸**,**文件系統**和** Windows **標記。 – DavidRR

回答

2

您的目標:找到這些目錄的絕對路徑而不是自己有子目錄。

我會打電話給那些感興趣的目錄終端目錄。這是我相信提供您尋找的便利功能的原型。該函數將其結果作爲列表返回。

my @list = find_terminal_directories($full_or_partial_path); 

而且這裏有find_terminal_directories()的實現。請注意,此實現的確不是而是需要使用任何全局變量。還要注意使用稱爲遞歸式的私人幫助函數

在我的Windows 7系統,爲輸入目錄C:/ Perl的/ lib目錄/測試,我得到的輸出:

== List of Terminal Folders == 
c:/Perl/lib/Test/Builder/IO 
c:/Perl/lib/Test/Builder/Tester 
c:/Perl/lib/Test/Perl/Critic 

== List of Files in each Terminal Folder: == 
c:/Perl/lib/Test/Builder/IO/Scalar.pm 
c:/Perl/lib/Test/Builder/Tester/Color.pm 
c:/Perl/lib/Test/Perl/Critic/Policy.pm 

實施

#!/usr/bin/env perl 

use strict; 
use warnings; 
use Cwd qw(abs_path getcwd); 

my @dir_list = find_terminal_directories("C:/Perl/lib/Test"); 
print "== List of Terminal Directories ==\n"; 
print join("\n", @dir_list), "\n"; 

print "\n== List of Files in each Terminal Directory: ==\n"; 
for my $dir (@dir_list) { 
    for my $file (<"$dir/*">) { 
     print "$file\n"; 
     open my $fh, '<', $file or die $!; 
     my $data = <$fh>; # slurp entire file contents into $data 
     close $fh; 

     # Now, do something with $data ! 
    } 
} 

sub find_terminal_directories { 
    my $rootdir = shift; 

    my @wanted; 
    my $cwd = getcwd(); 
    chdir $rootdir; 
    find_terminal_directories_helper(".", \@wanted); 
    chdir $cwd; 
    return @wanted; 
} 

sub find_terminal_directories_helper { 
    my ($dir, $wanted) = @_; 
    return if ! -d $dir; 
    opendir(my $dh, $dir) or die "open directory error!"; 
    my $count = 0; 
    foreach my $child (readdir($dh)) { 
     my $abs_child = abs_path($child); 
     next if (! -d $child || $child eq "." || $child eq ".."); 
     ++$count; 
     chdir $child; 
     find_terminal_directories_helper($abs_child, $wanted); # recursion! 
     chdir ".."; 
    } 
    push @$wanted, abs_path($dir) if ! $count; # no sub-directories found! 
} 
3
use File::Find; 

use strict; 
use warnings; 

my @dirs; 
my %has_children; 

find(sub { 
    if (-d) { 
     push @dirs, $File::Find::name; 
     $has_children{$File::Find::dir} = 1; 
    } 
}, 'D:/Temp'); 

my @ends = grep {! $has_children{$_}} @dirs; 

print "$_\n" for (@ends); 
+0

但是元素的索引並不像我期待的那樣。對於我來說,第一個元素應該是$ dir [0] =「D:/ Temp/A1/B1/C1」,但根據你的代碼獲得$ dir [0] =「D:/ Temp」。 – ImDrPatil

+0

@drp - 那麼,你只需要那些本身沒有子文件夾的文件夾的完整路徑? – DavidRR

+0

@DavidRR yep ... – ImDrPatil

0

我會用File::Find

示例腳本:

#!/usr/bin/perl 

use strict; 
use warnings; 

use File::Find; 

my $dir = "/home/chris"; 

find(\&wanted, $dir); 

sub wanted { 
    print "dir: $File::Find::dir\n"; 
    print "file in dir: $_\n"; 
    print "complete path to file: $File::Find::name\n"; 
} 

輸出:

$ test.pl 
dir: /home/chris/test_dir 
file in dir: test_dir2 
complete path to file: /home/chris/test_dir/test_dir2 
dir: /home/chris/test_dir/test_dir2 
file in dir: foo.txt 
complete path to file: /home/chris/test_dir/test_dir2/foo.txt 
... 
+0

[File :: Find :: Rule](http://search.cpan.org/~rclamp/File-Find-Rule-0.33/lib/File/Find/Rule.pm)建立在File :: Find上。 – Kenosis

+1

@Kenosis等等呢? – chrsblck

-1

使用反引號,寫子目錄和文件名爲文件列表文件:

`ls -R $dir > filelist` 
+3

OP如何在Windows環境中執行此操作? – Kenosis

2

或許下面會有所幫助:

use strict; 
use warnings; 
use File::Find::Rule; 

my $dir = "D:/Temp"; 
local $/; 

my @dirs = 
    sort File::Find::Rule->exec(sub { File::Find::Rule->directory->in($_) == 1 } 
)->directory->in($dir); 

for my $dir (@dirs) { 
    for my $file (<"$dir/*">) { 
     open my $fh, '<', $file or die $!; 
     my $data = <$fh>; 
     close $fh; 
     print $data; 
    } 
} 
  • local $/;讓我們啜食文件的內容到一個變量。如果您只想閱讀第一行,請將其刪除。
  • exec()sub用於傳遞只有那些不包含迪爾斯一個目錄
  • sort來安排你的通緝令那些迪爾斯
  • glob<"$dir/*">用於獲取的文件的文件每個目錄

編輯:已修改代碼以僅查找'終端目錄'。感謝DavidRR進行此規格說明。

+0

該OP澄清說,他只想處理*我所稱的**終端目錄** ......這些目錄本身不包含目錄。 (見[我的答案](http://stackoverflow.com/a/20558829/1497596)。)File :: Find :: Rule'功能很強大......你可以很容易地修改你的答案來添加額外的過濾只保留終端目錄? – DavidRR

+0

@DavidRR - 我錯過了這個規範,並感謝你的澄清。相應地修改了腳本。 – Kenosis

+0

優秀!這裏是[File :: Find :: Rule]的perldoc(http://search.cpan.org/~rclamp/File-Find-Rule-0.33/lib/File/Find/Rule.pm)。 – DavidRR

相關問題