Tôi đang tạo báo cáo dung lượng đĩa sử dụng File::Find
để thu thập kích thước tích lũy trong cây thư mục.Đường dẫn tệp vào cấu trúc dữ liệu JSON
Điều tôi nhận được (dễ dàng) từ File::Find
là tên thư mục.
ví dụ .:
/path/to/user/username/subdir/anothersubdir/etc
Tôi đang chạy File::Find
để thu thập kích thước bên dưới:
/path/to/user/username
Và xây dựng một báo cáo kích thước tích lũy của thư mục và mỗi người trong số các thư mục con.
Những gì tôi hiện đã có là: (. Và vâng, tôi biết đó không phải là rất đẹp)
while ($dir_tree) {
%results{$dir_tree} += $blocks * $block_size;
my @path_arr = split ("/", $dir_tree);
pop (@path_arr);
$dir_tree = join ("/", @path_arr);
}
.
Mục đích của việc này là vì vậy khi tôi stat
mỗi tệp, tôi thêm kích thước của nó vào nút hiện tại và mỗi nút cha trong cây.
này là đủ để tạo ra:
username,300M
username/documents,150M
username/documents/excel,50M
username/documents/word,40M
username/work,70M
username/fish,50M,
username/some_other_stuff,30M
Nhưng tôi muốn đến nay biến rằng trong để JSON hơn như thế này:
{
"name" : "username",
"size" : "307200",
"children" : [
{
"name" : "documents",
"size" : "153750",
"children" : [
{
"name" : "excel",
"size" : "51200"
},
{
"name" : "word",
"size" : "81920"
}
]
}
]
}
Đó là bởi vì tôi đang có ý định làm một D3 hình dung của cấu trúc này - dựa trên D3 Zoomable Circle Pack
Vì vậy, câu hỏi của tôi là - cách gọn gàng nhất để đối chiếu dữ liệu của tôi sao cho tôi có thể tích lũy (và lý tưởng nhất là không mulative) kích thước thông tin, nhưng populating một hash hierarchically.
Tôi đã suy nghĩ về một cách tiếp cận 'con trỏ' (và sử dụng File::Spec
thời gian này):
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}
}
Mặc dù ... đó là không hoàn toàn tạo ra các cấu trúc dữ liệu tôi đang tìm kiếm, không kém phần quan vì về cơ bản chúng tôi phải tìm kiếm bằng khóa băm để thực hiện phần 'cuộn lên' của quy trình.
Có cách nào tốt hơn để hoàn thành việc này không?
Edit - ví dụ hoàn chỉnh hơn về những gì tôi có đã:
#!/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";
}
}
Và vâng - Tôi biết điều này là không di động, và thực hiện một vài điều hơi khó chịu. Một phần của những gì tôi đang làm ở đây đang cố gắng cải thiện điều đó. (Nhưng hiện nay nó là một cấu trúc homedir dựa trên Unix, vì vậy đó là tốt).
Bạn có thể thêm một ví dụ hoàn chỉnh mà tôi lười biếng có thể sao chép/dán xin vui lòng? – simbabque
OK, chịu với tôi. Sẽ phải cắt tập lệnh của tôi xuống một chút. – Sobrique
OK. Đã thêm một ví dụ tối thiểu. (Nó bỏ qua rất nhiều rác, giống như một số định dạng đơn vị và kết quả đầu ra tóm tắt khác nhau). – Sobrique