2012-05-15 37 views
2

爲了遍歷目錄,我仍然使用很棒的Path::Class模塊。我寫了一段代碼,但對輸出的顯示不滿意。我的目錄樹輸出不像tree命令的輸出那樣乾淨利落。 :-(樹狀命令顯示目錄樹輸出

我迄今爲止代碼:

use strict; 
use warnings; 
use Path::Class; 

my $dir = Path::Class::Dir->new('D:\dev\pl\testdir'); 

my $max_depth = $dir->traverse(sub { 
    my ($child, $cont, $depth) = @_; 
    return max($cont->($depth + 1), $depth); 
}, 0); 
sub max { my $max = 0; for (@_) { $max = $_ if $_ > $max } $max }; 

# Print header 
printf "%-43s|%s\n", " Name", " mtime"; 
printf "%-43s|%s\n", '-' x 43, '-' x 11; 

$dir->traverse(sub { 
    my ($child, $cont, $indent) = @_; 
    my $child_basename = $child->basename; 
    my $child_stat  = $child->stat(); 
    my $child_mtime = $child_stat->[9]; 
    $indent //= 0; 
    my $width = 40 - 3 * ($indent - 1); 

    #print "DEBUG: Scanning $child\n"; 

    if ($indent == 0) { 
    print "ROOT: ", $child, "\n"; 
    } 
    else { 
    if ($child->is_dir) { 
     print ' ' x ($indent - 1), '+- '; 
     printf "%-${width}s| %d", $child_basename . '/', $child_mtime; 
     print "\n"; 
    } else { 
     print ' ' x ($indent - 1), '|- '; 
     printf "%-${width}s| %d", $child_basename, $child_mtime; 
     print "\n"; 
    } 
    } 

    $cont->($indent + 1); 
}); 

而且我錯誤輸出爲:

Name          | mtime 
-------------------------------------------|----------- 
ROOT: D:\dev\pl\testdir 
+- Path-Class-0.25/      | 1337013211 
    |- Build.PL        | 1329360988 
    |- Changes        | 1329360988 
    |- dist.ini        | 1329360988 
    |- INSTALL        | 1329360988 
    +- lib/         | 1337013211 
     +- Path/        | 1337013211 
     +- Class/       | 1337013211 
      |- Dir.pm      | 1329360988 
      |- Entity.pm     | 1329360988 
      |- File.pm      | 1329360988 
     |- Class.pm      | 1329360988 
    |- LICENSE        | 1329360988 
    |- Makefile.PL       | 1329360988 
    |- MANIFEST        | 1329360988 
    |- META.yml        | 1329360988 
    |- README        | 1329360988 
    |- SIGNATURE       | 1329360988 
    +- t/         | 1337013211 
     |- 01-basic.t      | 1329360988 
     |- 02-foreign.t      | 1329360988 
     |- 03-filesystem.t     | 1329360988 
     |- 04-subclass.t      | 1329360988 
     |- 05-traverse.t      | 1329360988 
     |- author-critic.t     | 1329360988 

正確輸出(也更好看)應該是:

Name          | mtime 
-------------------------------------------|----------- 
ROOT: D:\dev\pl\testdir 
+- Path-Class-0.25/      | 1337013211 
    |- Build.PL        | 1329360988 
    |- Changes        | 1329360988 
    |- dist.ini        | 1329360988 
    |- INSTALL        | 1329360988 
    +- lib/         | 1337013211 
    | +- Path/        | 1337013211 
    |  +- Class/       | 1337013211 
    |  | |- Dir.pm      | 1329360988 
    |  | |- Entity.pm     | 1329360988 
    |  | |- File.pm      | 1329360988 
    |  \- Class.pm      | 1329360988 
    |- LICENSE        | 1329360988 
    |- Makefile.PL       | 1329360988 
    |- MANIFEST        | 1329360988 
    |- META.yml        | 1329360988 
    |- README        | 1329360988 
    |- SIGNATURE       | 1329360988 
    \- t/         | 1337013211 
     |- 01-basic.t      | 1329360988 
     |- 02-foreign.t      | 1329360988 
     |- 03-filesystem.t     | 1329360988 
     |- 04-subclass.t      | 1329360988 
     |- 05-traverse.t      | 1329360988 
     \- author-critic.t     | 1329360988 

你能否請改善或糾正我的代碼?

非常感謝您的幫助!

問候,
斯科特

+0

如果唯一的區別是每個目錄的最後一個孩子應該擁有的,而不是垂直條通往上面有一條斜線(順便說一句,你可以在問題中說),我認爲你必須保存每個孩子的信息,直到所有的孩子都被處理完畢,然後把它們打印出來。 –

+0

哦,我發現你在這些行上沒有出現多個'|'也有區別。 –

回答

3

下面我的代碼並不花哨的解決方案,但它工作在你希望>>

#!/usr/bin/perl 

use strict; 
use warnings; 
use Path::Class; 

my $dir = Path::Class::Dir->new('D:\dev\pl\testdir'); 

my $max_depth = $dir->traverse(sub { 
    my ($child, $cont, $depth) = @_; 
    return max($cont->($depth + 1), $depth); 
}, 0); 

sub max { my $max = 0; for (@_) { $max = $_ if $_ > $max } $max }; 

my @output = (sprintf("%-43s|%s", " Name", " mtime"), 
       sprintf("%-43s|%s", '-' x 43, '-' x 11)); 

my @tree = (0, 0); 
my $last_indent = 0; 

$dir->traverse(sub { 
    my ($child, $cont, $indent) = @_; 
    my $child_basename = $child->basename; 
    my $child_stat  = $child->stat(); 
    my $child_mtime = $child_stat->[9]; 

    $indent = 1 if (!defined $indent); 
    my $width = 40 - 3 * ($indent - 1); 

    if ($last_indent != $indent) { 
    if ($last_indent > ($indent + 1)) { 
     for my $level (($indent + 1)..($last_indent - 1)) { 
     $output[$#output - $_] = 
      substr($output[$#output - $_], 0, 3 * ($level - 1)) . ' ' . 
      substr($output[$#output - $_], 3 * ($level - 1) + 1, 65535) 
      for (0..$tree[$level] - 1); 
     } 
     delete $tree[$_] for $indent..$last_indent; 
    } 
    $tree[$indent] = 0; 
    $last_indent = $indent; 
    } 

    if ($child->is_dir) { 
    push @output, sprintf("%s+- %-${width}s| %d", 
     ('| ' x ($indent - 1)), $child_basename . '/', $child_mtime); 
    $tree[$indent] = 0; 
    } 
    else { 
    push @output, sprintf("%s%s- %-${width}s| %d", ('| ' x ($indent - 1)), 
     ($child eq ($child->dir->children)[-1] ? '\\' : '|'), 
     $child_basename, $child_mtime); 
    $tree[$indent]++; 
    } 
    $tree[$_]++ for (1..$indent - 1); 

    $cont->($indent + 1); 
}); 

for my $level (1..$last_indent - 1) { 
    $output[$#output - $_] = 
    substr($output[$#output - $_], 0, 3 * ($level - 1)) . ' ' . 
    substr($output[$#output - $_], 3 * ($level - 1) + 1, 65535) 
     for (0..$tree[$level] - 1); 
} 

print "$_\n" for @output; 
+0

非常感謝!很棒。 :-) – Scottie

0
if ($child->is_dir) { 
    printf "%s+- %-${width}s| %d\n", 
     ('| ' x ($indent - 1)), 
     $child_basename . '/', 
     $child_mtime; 
} else { 
    printf "%s%s- %-${width}s| %d\n", 
     ('| ' x ($indent - 1)), 
     ($child eq ($child->dir->children)[-1] ? '\\' : '|'), 
     $child_basename, 
     $child_mtime; 
} 

此外,ASCII行導致眼癌。改爲使用正確的box drawing characters

+0

謝謝!它效果更好但不理想 - 有些線條是不必要的。 – Scottie

+0

P.S. [不必要的行](http://i.imgur.com/V1FT6.png) – Scottie

+0

我沒有耐心去編程這個變化,我今天很快就辭職了。我會給你提示修改的內容:對於第一個'%s'表達式,用'parent' $ indent時間查找樹,然後在標量上下文中調用'children'。如果該目錄有多個孩子,則輸出一個「'| ''分段,如果只有一個孩子,輸出一個''''分段。 – daxim