通过代码实现gz压缩,并保持原来的文件名

写这篇博客主要是为了记录一下这两天来的研究成果-gz带原有文件名压缩。首先要说的是这个解决方案不是通过调用命令gzip来做的,而是通过java代码来实现的,其中用到了apache的common compress类库。

首先来了解一下问题:

对于gz文件,我想对于使用Linux的同学们来说应该非常的熟悉了。那好,现在有一个文件叫a.txt, 我现在要把它压缩成b.gz。可以猜想一下,解压后的文件是

1. a.txt

2. b.txt

3. b

猜到了没,答案是3。为什么?为什么用gzip -c压缩a.txt,解压出来还是a.txt。而使用代码(通常是GZIPOutputStream)压缩后,解压的却是b,而且连个扩展名也没有。

这个问题还得从gz的设计目的说起。对于gz这种压缩格式,设计当初的目的是用来压缩单个平面文件的。也就是说如果想压缩多个文件,就要用到tar命令。如果想保留原文件名就要用文件名+.gz来做,如a.txt -> a.txt.gz。默认情况下,gz并不负责对文件名的处理。那么gzip -c又是如何做到保留原文件名这点的呢?

这里就要说一下gz的文件格式标准了,参见gz文件格式RFC。里面明确提到了在gz文件头里有一个标志位用于控制gz文件的一下扩展属性。

+---+---+---+---+---+---+---+---+---+---+
|ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
+---+---+---+---+---+---+---+---+---+---+
(if FLG.FEXTRA set)
+---+---+=================================+
| XLEN  |...XLEN bytes of "extra field"...| (more-->)
+---+---+=================================+
(if FLG.FNAME set)
+=========================================+
|...original file name, zero-terminated...| (more-->)
+=========================================+
(if FLG.FCOMMENT set)
+===================================+
|...file comment, zero-terminated...| (more-->)
+===================================+
(if FLG.FHCRC set)
+---+---+
| CRC16 |
+---+---+
+=======================+
|...compressed blocks...| (more-->)
+=======================+
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
|     CRC32     |     ISIZE     |
+---+---+---+---+---+---+---+---+

一个实际的gz文件样子

红色部分的是FNAME标志位,以及附带的文件名。一旦设置了这两个属性,gz在解压缩时候就会自动使用附带的文件名来命名解压文件了。那么写到这里,gzip命令的实现原理就已经清楚了。接下来就要分析一下为什么常规的代码无法实现这一功能。

 

posted @ 2014-01-01 00:27  moonz-wu  阅读(1800)  评论(0编辑  收藏  举报