Как описано в комментариях выше, последние 4 байта содержат isize
Вот некоторый код, который я написал для вычисления несжатых байтов, заданных путем к файлу:
sub get_isize
{
my ($file) = @_;
my $isize_len = 4;
# create a handle we can seek
my $FH;
unless( open( $FH, '<:raw', $file ) )
{
die "Failed to open $file: $!";
}
my $io;
my $FD = fileno($FH);
unless( $io = IO::Handle->new_from_fd( $FD, 'r' ) )
{
die "Failed to create new IO::Handle for $FD: $!";
}
# seek back from EOF
unless( $io->IO::Seekable::seek( "-$isize_len", 2 ) )
{
die "Failed to seek $isize_len from EOF: $!"
}
# read from here into mod32_isize
my $mod32_isize;
unless( my $bytes_read = $io->read( $mod32_isize, $isize_len ) )
{
die "Failed to read $isize_len bytes; read $bytes_read bytes instead: $!";
}
# convert mod32 to decimal by unpacking value
my $dec_isize = unpack( 'V', $mod32_isize );
return $dec_isize;
}
Для несжатых файлов размером более 4 ГБ вам нужно будет угадать, следует ли добавить 4 ГБ к полученному размеру на основе ожидаемого минимального коэффициента сжатия.
use constant MIN_COMPRESS_FACTOR => 200;
my $outer_bytes = ( -s $path );
my $inner_bytes = get_isize( $path );
$bytes += 4294967296 if( $inner_bytes < $outerbytes * MIN_COMPRESS_FACTOR );
Если ваш несжатый файл больше, чем 4294967296 * 2, то вам нужно будет угадать, сколько кратных 4294967296 применить (хотя я никогда не проверял это), однако вам нужно иметь точного судью ожидаемой степени сжатия для этого отработать:
my $estimated_multiplier = int( ($outerbytes * MIN_COMPRESS_FACTOR) / 4294967296 );
$bytes += ( 4294967296 * $estimated_multiplier ) if( $estimated_multiplier );