我有一堆非常大的文件(大小为几千兆字节),它们具有非常高的压缩比(1:200或更高)。我必须处理这些,并希望至少显示某种进度估计。出于这个原因,我想知道.gz中文件的大小,所以我可以将它与我已经提取的内容进行比较。
然而,由于每次提前打开整个文件包装是相当令人望而却步的,而且浪费时间,我想在没有这样做的情况下确定尺寸。
我知道这是可能的。我可以用Total Commander打开gzip文件,查看器插件会显示正确的大小。 (我知道它不会解压缩,因为它会立即向我显示大小,这对于gzip中的10GB文件来说是不可能的。)
可能有一些标题字段包含该信息。
然而,通过各种CPAN模块的文档,我找不到适合该法案的任何内容。 IO::Uncompress::Gunzip允许我访问 标头,但它不包含任何文件大小信息。
有什么建议吗?
答案 0 :(得分:1)
对此有正确答案:
sub get_gz_size {
my ( $gz_file ) = @_;
my @raw = `gzip --list $gz_file`;
my $size = ( split " ", $raw[1] )[1];
return $size;
}
答案 1 :(得分:1)
如上面的评论中所述,最后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;
}
对于大于4Gb的未压缩文件,您需要根据预期的最小压缩因子猜测是否将4Gb添加到检索到的isize中。
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 );