【发布时间】:2015-11-29 05:06:33
【问题描述】:
我正在做一个磁盘空间报告,它使用File::Find 来收集目录树中的累积大小。
我从File::Find(很容易)得到的是目录名称。
例如:
/path/to/user/username/subdir/anothersubdir/etc
我正在运行File::Find 来收集下面的尺寸:
/path/to/user/username
并构建目录和每个子目录的累积大小报告。
我目前得到的是:
while ( $dir_tree ) {
%results{$dir_tree} += $blocks * $block_size;
my @path_arr = split ( "/", $dir_tree );
pop ( @path_arr );
$dir_tree = join ( "/", @path_arr );
}
(是的,我知道这不是很好。)。
这样做的目的是当我stat每个文件时,我将它的大小添加到当前节点和树中的每个父节点。
这足以生成:
username,300M
username/documents,150M
username/documents/excel,50M
username/documents/word,40M
username/work,70M
username/fish,50M,
username/some_other_stuff,30M
但我现在想把它转换成 JSON,更像这样:
{
"name" : "username",
"size" : "307200",
"children" : [
{
"name" : "documents",
"size" : "153750",
"children" : [
{
"name" : "excel",
"size" : "51200"
},
{
"name" : "word",
"size" : "81920"
}
]
}
]
}
那是因为我打算对此结构进行 D3 可视化 - 大致基于 D3 Zoomable Circle Pack
所以我的问题是 - 整理我的数据的最简洁的方法是什么,以便我可以获得累积(最好是非累积)大小信息,但分层填充哈希。
我在考虑“光标”方法(这次使用File::Spec):
use File::Spec;
my $data;
my $cursor = \$data;
foreach my $element ( File::Spec -> splitdir ( $File::Find::dir ) ) {
$cursor -> {size} += $blocks * $block_size;
$cursor = $cursor -> {$element}
}
虽然...这并没有完全创建我正在寻找的数据结构,尤其是因为我们基本上必须通过哈希键进行搜索才能完成该过程的“汇总”部分。
有没有更好的方法来做到这一点?
编辑 - 我已经拥有的更完整示例:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use Data::Dumper;
my $block_size = 1024;
sub collate_sizes {
my ( $results_ref, $starting_path ) = @_;
$starting_path =~ s,/\w+$,/,;
if ( -f $File::Find::name ) {
print "$File::Find::name isafile\n";
my ($dev, $ino, $mode, $nlink, $uid,
$gid, $rdev, $size, $atime, $mtime,
$ctime, $blksize, $blocks
) = stat($File::Find::name);
my $dir_tree = $File::Find::dir;
$dir_tree =~ s|^$starting_path||g;
while ($dir_tree) {
print "Updating $dir_tree\n";
$$results_ref{$dir_tree} += $blocks * $block_size;
my @path_arr = split( "/", $dir_tree );
pop(@path_arr);
$dir_tree = join( "/", @path_arr );
}
}
}
my @users = qw ( user1 user2 );
foreach my $user (@users) {
my $path = "/home/$user";
print $path;
my %results;
File::Find::find(
{ wanted => sub { \&collate_sizes( \%results, $path ) },
no_chdir => 1
},
$path
);
print Dumper \%results;
#would print this to a file in the homedir - to STDOUT for convenience
foreach my $key ( sort { $results{$b} <=> $results{$a} } keys %results ) {
print "$key => $results{$key}\n";
}
}
是的 - 我知道这不是便携式的,并且会做一些有些讨厌的事情。我在这里所做的部分工作是试图改进这一点。 (但目前它是一个基于 Unix 的 homedir 结构,所以没关系)。
【问题讨论】:
-
你能添加一个完整的例子,我可以懒惰地复制/粘贴吗?
-
好的,请耐心等待。将不得不将我的脚本缩小一点。
-
好的。添加了一个最小的示例。 (它省略了很多垃圾,比如一些单位格式和不同的摘要输出)。
-
似乎是一种非常直接的方法。
-
是的。但根本不能很好地导出到 JSON。