获取GZIPped文件属性(例如' gzip -l',基本压缩率)

时间:2015-01-07 18:14:50

标签: java gzip

我有一个非常大的gzip文件树目录,我需要计算未压缩的大小。 由于我所说的不仅仅是600GB(已压缩),我相信解压缩每个文件以验证大小并不是正确的方法。

Unix shell上,我使用命令gzip -l轻松完成此任务,列出压缩比,压缩和未压缩大小的文件夹上的每个文件。

虽然,我发现的与GZIP相关的Java库只是用于压缩和解压缩的Streams。

如果gzip命令可以在不触及文件的情况下检索此信息,我认为必须在文件的某种标题上指定此数据。在不解压缩文件的情况下访问此信息的方法是什么?

2 个答案:

答案 0 :(得分:3)

根据GZIP规范RFC 1952,GZIP块的最后4个字节是未压缩的数据大小。该值存储在little endian中。大多数gzip压缩文件只有1个块,因此这将是文件的最后4个字节。

例如,我只是压缩了一个未压缩大小为29963246字节的文件。 gzip文件中的最后4个字节是

EE 33 C9 01

当读取小端(从右到左)0x1C933EE = 29963246

这里只是通过读取小端的最后4个字节来快速而肮脏地获取未压缩文件的大小:

File f = ...
try(RandomAccessFile ra =new RandomAccessFile(f, "r");
    FileChannel channel = ra.getChannel()){

        MappedByteBuffer fileBuffer = channel.map(MapMode.READ_ONLY, f.length()-4, 4);
        fileBuffer.load();

        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.order(ByteOrder.LITTLE_ENDIAN);


        buf.put(fileBuffer);
        buf.flip();
        //will print the uncompressed size
        //getInt() reads the 4 bytes as a int
        // if the file is between 2GB and 4GB
        // then this will return a negative value
        //and you'll have to do your own converting to an unsigned int
        System.out.println(buf.getInt());
    }

修改

请注意,这仅适用于仅有1个压缩块的gzip压缩文件(大多数文件<4GB)。如果您有一个包含多个gzip压缩块的文件,则只返回最后一个块的大小。由于规范只为该大小分配4个字节,我假设一个&gt; 4GB的文件将被分成多个GZIP块。

更强大的版本是解析每个gzip块以获得每个块的未压缩大小。 GZIP标头也具有压缩数据的大小,因此您必须解析每个GZIP块标头,获取压缩数据的长度,寻找该长度以获得GZIP块的结束,然后获得未压缩的大小以进行总结。然后继续解析任何其他GZIP块,直到你达到EOF。

答案 1 :(得分:0)

看看Apache Commons Compress,它支持gzip。它还有一个类&#39; org.apache.commons.compress.compressors.gzip.GzipParameters&#39;这可能会有所帮助。