在我的程序中,我需要查找许多文件的校验和。校验和计算在find命令中。
find(sub {
my $file = $File::Find::name;
return if ! length($file);
open (FILE, "$file");
my $chksum = md5_base64(<FILE>);
close FILE;
}, "/home/nijin");
以上代码完美无缺。但是如果在/ home / nijin路径中有一个大小的文件,例如6GB,它将把6 GB加载到RAM内存中,并且该过程连续占用6 GB RAM,直到该过程完成。请注意,这是一个备份过程,完成此过程需要12个多小时。所以我将失去6GB,直到完成该过程。最糟糕的情况是由于大量内存使用而导致进程挂起。作为一种选择,我尝试使用File::Map
。代码粘贴在下面。
find(sub {
my $file = $File::Find::name;
return if ! length($file);
map_file my $map, "$filename", '<';
my $chksum = md5_base64($map);
}, "/home/nijin");
上面的代码也有效但我在使用上面的代码时遇到了分段错误错误。我也试过Sys::Mmap
,但问题与第一个问题相同。还有其他选择吗?
答案 0 :(得分:5)
我会在子进程中运行昂贵的计算。这使父进程保持适当的内存消耗。孩子可以为大文件占用大量内存,但是一旦返回MD5,内存就会返回给操作系统:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use File::Find;
use Digest::MD5 qw{ md5_base64 };
my %md5;
find(sub {
my $name = $File::Find::name;
return unless -f;
my $child_pid = open(my $CMD, '-|') // die "Can't fork: $!";
if ($child_pid) { # Parent
$md5{$name} = <$CMD>;
wait;
} else { # Child
open my $IN, '<', $_ or die "$name: $!";
print md5_base64(<$IN>);
exit;
}
}, shift);
print Dumper \%md5;
答案 1 :(得分:3)
没有理由一次将整个文件读入内存。
您可以通过以下方式以64k块显式处理它:
my $chksum = do {
open my $fh, '<:raw', $file;
my $md5 = Digest::MD5->new;
local $/ = \65536; # Read 64k at once
while (<$fh>) {
$md5->add($_);
}
$md5->hexdigest;
};
# Do whatever you were going to do with it here
您也可以直接传递文件句柄,但这并不能保证它如何处理它:
my $chksum = do {
open my $fh, '<:raw', $file;
Digest::MD5->new->addfile($fh)->hexdigest
};