Perl 重复使用计算md5(或任何其他校验和)

Perl 重复使用计算md5(或任何其他校验和),perl,Perl,试图为深层目录树中的所有文件计算增量md5摘要,但我无法“重用”已计算的摘要 以下是我的测试代码: #/usr/bin/env perl 使用5.014; 使用警告; 使用Digest::MD5; 使用路径::微小; #在tempdir中创建一些测试文件 my@filename=qw(a-b); my$testdir=Path::Tiny->tempdir; $testdir->child($\子)->spew($\子)用于@filename#创建2个文件 dirmd5($testdir,@fi

试图为深层目录树中的所有文件计算增量
md5
摘要,但我无法“重用”已计算的摘要

以下是我的测试代码:

#/usr/bin/env perl
使用5.014;
使用警告;
使用Digest::MD5;
使用路径::微小;
#在tempdir中创建一些测试文件
my@filename=qw(a-b);
my$testdir=Path::Tiny->tempdir;
$testdir->child($\子)->spew($\子)用于@filename#创建2个文件
dirmd5($testdir,@filename);
出口
子目录MD5{
我的($dir,@files)=@;
my$dirctx=Digest::MD5->new;#整个目录的MD5
对于我的$fname(@files){
#计算一个文件的md5
my$filectx=Digest::MD5->new;
my$fd=$dir->child($fname)->openr\u raw;
$filectx->addfile($fd);
收盘价$fd;
说“md5 for$fname:”,$filectx->clone->hexdigest;
#想要将上面的file-md5“添加”到目录md5中吗
#这不起作用-即使$filectx没有重置(注意上面的“克隆”)
#$dirctx->add($filectx);
#用于添加文件,如下所示:,
#但是,这将再次计算md5
#例如,对于每个文件,计算进行两次。。。
#仅文件一次(如上)
#第二次是目录
#如果文件太多太大,那就太糟糕了(
#特别是,如果我想计算整个目录树的md5sum
$fd=$dir->child($fname)->openr\u raw;
$dirctx->addfile($fd);
收盘价$fd;
}
说“md5 for dir:”,$dirctx->hexdigest;
}
上述印刷品:

md5 for a  : 0cc175b9c0f1b6a831c399e269772661
md5 for b  : 92eb5ffee6ae2fec3ad71c777531578f
md5 for dir: 187ef4436122d1cc2f40dc2b92f0eba0
这是正确的,但不幸的是效率低下

在阅读中,我没有找到任何方法重用已经计算的md5。例如,如上所述
$dirctx->add($filectx);
。这可能是不可能的

存在任何允许重用已计算的校验和的校验和的方法,因此,我可以为整个目录树计算校验和/摘要,而不需要为每个文件多次计算摘要


参考:尝试稍微解决否。没有任何东西与
MD5(初始数据)
MD5(新数据)
有关
MD5(初始数据+新数据)
因为数据在流中的位置与其值同样重要。否则它将不是一个非常有用的错误检查,因为
aba
aab
baa
都具有相同的校验和

如果文件足够小,你可以将每个文件读入内存,并使用该副本将数据添加到两个摘要中。这样可以避免从大容量存储器中读取两次

#!/usr/bin/env perl

use 5.014;
use warnings 'all';

use Digest::MD5;
use Path::Tiny;

# create some test-files in the tempdir
my @filenames = qw(a b);
my $testdir   = Path::Tiny->tempdir;
$testdir->child($_)->spew($_) for @filenames; # create 2 files

dirmd5($testdir, @filenames);

sub dirmd5 {
    my ($dir, @files) = @_;

    my $dir_ctx = Digest::MD5->new;  #the md5 for the whole directory

    for my $fname ( @files ) {

        my $data = $dir->child($fname)->slurp_raw;

        # calculate the md5 for one file
        my $file_md5 = Digest::MD5->new->add($data)->hexdigest;
        say "md5 for $fname  : $file_md5";

        $dir_ctx->add($data);
    }

    my $dir_md5 = $dir_ctx->hexdigest;
    say "md5 for dir: $dir_md5";
}
如果文件很大,那么剩下的唯一优化就是避免重新打开同一个文件,而是在第二次读取之前将其倒回起始位置

#!/usr/bin/env perl

use 5.014;
use warnings 'all';

use Digest::MD5;
use Path::Tiny;
use Fcntl ':seek';

# create some test-files in the tempdir
my @filenames = qw(a b);
my $testdir   = Path::Tiny->tempdir;
$testdir->child($_)->spew($_) for @filenames; # create 2 files

dirmd5($testdir, @filenames);

sub dirmd5 {
    my ($dir, @files) = @_;

    my $dir_ctx = Digest::MD5->new;  # The digest for the whole directory

    for my $fname ( @files ) {

        my $fh = $dir->child($fname)->openr_raw;

        # The digest for just the current file
        my $file_md5 = Digest::MD5->new->addfile($fh)->hexdigest;
        say "md5 for $fname  : $file_md5";

        seek $fh, 0, SEEK_SET;
        $dir_ctx->addfile($fh);
    }

    my $dir_md5 = $dir_ctx->hexdigest;
    say "md5 for dir: $dir_md5";
}

啊,是这样的。那么,尝试计算包含多个嵌套目录的整个目录树的摘要是毫无意义的,因为我需要为“上面”的每个目录一次又一次地计算每个文件的摘要……啊……:(需要为这个问题找出一些其他的“逻辑”)"。谢谢。@cajwine:没必要这样做。只需为树中的每个文件及其每个祖先目录保留一个摘要。任何文件中的数据都必须添加到每个祖先目录的摘要中。这与计算树中每个目录的大小几乎相同,只是不能只为最后,孩子们在一起。