Perl: Как мне получить "чтение байтов" из md5 :: digest addfile ()? - PullRequest
1 голос
/ 16 апреля 2019

Я использую Digest :: MD5 для вычисления MD5 потока данных; а именно GZIP-файл (или, если быть точным, 3000), который слишком велик, чтобы поместиться в ОЗУ. Итак, я делаю это:

 use Digest::MD5 qw(md5_base64);

 my ($filename) = @_;                # this is in a sub
 my $ctx = Digest::MD5 -> new;

 $openme = $filename;        # Usually, it's a plain file
 $openme = "gunzip -c '$filename' |" if ($filename =~ /\.gz$/); # is gz

 open (FILE, $openme); # gunzip to STDOUT
 binmode(FILE);
 $ctx -> addfile(*FILE);   # passing filehandle
 close(FILE);

Это успех. addfile аккуратно хлебает на выходе gunzip и выдает правильный MD5.

Однако мне бы очень хотелось узнать размер скрытых данных (в этом случае «заархивированный» файл).

Я мог бы добавить еще

  $size = 0 + `gunzip -c very/big-file.gz | wc -c`;

но для этого нужно прочитать файл дважды.

Есть ли способ извлечь количество байтов, извлеченных из Digest :: MD5? Я попытался захватить результат: $result = $ctx -> addfile(*FILE); и выполнить Data :: Dumper как для $ result, так и для $ ctx, но ничего интересного не произошло.

Редактировать: файлы часто не распаковываются. Добавлен код, чтобы показать, что я действительно делаю.

Ответы [ 2 ]

3 голосов
/ 16 апреля 2019

Я бы сделал все это на Perl, не полагаясь на внешнюю программу для распаковки:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use IO::Uncompress::Gunzip qw/$GunzipError/;
use Digest::MD5;

my $filename = shift or die "Missing gzip filename!\n";

my $md5 = Digest::MD5->new;
# Allow for reading both gzip format files and uncompressed files.
# This is the default behavior, but might as well be explicit about it.
my $z = IO::Uncompress::Gunzip->new($filename, Transparent => 1)
  or die "Unable to open $filename: $GunzipError\n";
my $len = 0;

while ((my $blen = $z->read(my $block)) > 0) {
  $len += $blen;
  $md5->add($block);
}
die "There was an error reading the file: $GunzipError\n" unless $z->eof;

say "Total uncompressed length: $len";
say "MD5: ", $md5->hexdigest;

Если вы хотите использовать gunzip вместо основного IO::Uncompress::Gunzip модуля, вы можете сделать нечто подобное, используя read для получения порции данных за раз:

#!/usr/bin/perl
use warnings;
use strict;
use autodie; # So we don't have to explicitly check for i/o related errors
use feature qw/say/;
use Digest::MD5;

my $filename = shift or die "Missing gzip filename!\n";

my $md5 = Digest::MD5->new;
# Note use of lexical file handle and safer version of opening a pipe
# from a process that eliminates shell shenanigans. Also uses the :raw
# perlio layer instead of calling binmode on the handle (which has the
# same effect)
open my $z, "-|:raw", "gunzip", "-c", $filename;
# Non-compressed version
# open my $z, "<:raw", $filename;
my $len = 0;

while ((my $blen = read($z, my $block, 4096)) > 0) {
  $len += $blen;
  $md5->add($block);
}

say "Total uncompressed length: $len";
say "MD5: ", $md5->hexdigest;
2 голосов
/ 16 апреля 2019

Вы можете прочитать содержимое самостоятельно и передать его в $ctx->add($data) и вести постоянный подсчет того, через сколько данных вы прошли.Независимо от того, добавляете ли вы все данные за один вызов или за несколько вызовов, это не имеет никакого значения для базового алгоритма.Документы включают в себя:

    All these lines will have the same effect on the state of the $md5 object:

        $md5->add("a"); $md5->add("b"); $md5->add("c");
        $md5->add("a")->add("b")->add("c");
        $md5->add("a", "b", "c");
        $md5->add("abc");

, что указывает на то, что вы можете просто сделать это за раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...