在 Perl 中计算 32mb 文件的熵 - 最快的方法是什么?

Calculating the entropy of a 32mb file in Perl - What is the quickest method?

我有一个 32,678kb 的加密 bin 文件,我需要它的熵。我正在使用 Perl 作为一个更大项目的一部分。

到目前为止我使用了以下 'technique':

use Shannon::Entropy qw/entropy/;
my $file = "test.bin";
open(my $bin, "<", $file) or die $!; binmode $bin;
seek($bin, 0x000000, 0); 
read($bin, my $entropy, 0x01FFFFF0);
print entropy($entropy);

这会产生几乎无限的等待时间,以至于我在 30 多分钟后就放弃了。

我不能偏离测试整个文件的熵。

有没有更快的方法?将其拆分、对其进行熵处理并使用一些奇怪的数学再次组合会产生与一个文件相同的熵吗?

这是为避免所有地图调用而重新编写的熵函数

sub entropy {
    my ($entropy, $len, $p, %t) = (0, length($_[0]));
    my @chars = split '', $_[0];
    $t{$_}++ foreach @chars;

    foreach (values %t) {
        $p = $_/$len;
        $entropy -= $p * log $p ;
    }       

    return $entropy / log 2;
}

它可能对您来说更快

我已经重新考虑过这个问题。您实际上不需要将文件拖入内存。 $len是文件的长度,可以从-s $file_name得到,%t是频率table,可以通过一次读取一个块来计算。因此,计算文件熵的函数版本为

sub file_entropy {
    my ($file_name) = @_;

    # Get number of bytes in file
    my $len = -s $file_name;
    my ($entropy, %t) = 0;

    open (my $file, '<:raw', $file_name) || die "Cant open $file_name\n";

    # Read in file 1024 bytes at a time to create frequancy table
    while( read( $file, my $buffer, 1024) ) {
        $t{$_}++ 
            foreach split '', $buffer;

        $buffer = '';
    }

    foreach (values %t) {
        my $p = $_/$len;
        $entropy -= $p * log $p ;
    }       

    return $entropy / log 2;
}