Note:本文的工具都开源在GitHub的JUtils上。
ZIP压缩
zipOutputStream方式
压缩
这个方式是最基础的方式,是Java底层给出的一种流方案。
其压缩方式步骤如下:
- 新建一个
ZipOutputStream
,其参数接收一个OutputStream
,一般是新建一个FileOutputStream。 - 循环获取要压缩的文件/文件夹,调用putEntry函数进行流的写入。
- putEntry的过程如下:
- 如果是文件夹,则将其设为基础目录,然后递归调用putEntry来压缩该文件夹下的文件。
- 如果是文件,则使用基础目录拼接后将该entry放入流中。
- 设置压缩级别。
- flush、close这个流。
值得注意的有:
- 文件夹的处理,即递归的获取子文件夹,然后进行压缩。
- entry的名字则自带了文件夹目录层级,即
xxx/aaaa.jpg
则会在压缩包中新建一个xxx的文件夹,并把aaa.jpg
放入其中。
具体如下:
1 | /*** |
解压
解压的过程就比较简单了,因为不涉及递归获取文件。其过程如下:
- 只需要不断调用
getNextEntry
方法,获取entry,判断其为文件夹还是文件:- 如果是文件夹,则结合基础目录,拼接新目录并新建该文件夹。
- 如果是文件,则结合基础目录,拼接新文件目录,然后读取流中的文件并写入该文件。
- 关闭Entry、关闭流。
代码如下:
1 | public static void extractZipByStream(String zipPath) throws IOException { |
遇到的坑
entry.getSize()
:这个接口返回对应entry未压缩时的大小。但是其可能是未知的,所以不能通过该属性来新建byte数组。文件流读取:就像上面说的,
entry.getSize()
可能是未知的。所以流读取的时候,应当采用先初始化一个固定大小的数组,然后调用read时传入该数组的大小,这里是1024。但是read会返回当次读取的字节长度,如果小于1024,则返回该次的大小,否则就是传入的大小(1024)。还得注意中文,如果文件中含有中文,那必须在新建流的时候,传入第二个编码参数。
1
2
3ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipPath), Charset.forName("GBK"));
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipPath), Charset.forName("GBK"));
ZipFile方式
ZipFile类可以用来读取zip文件,其实本质上还是利用ZipInputStream
,所以其只可以用来解压缩文件。但是由于其对压缩包的每个文件都进行拆解,所以相较于直接用ZipInputStream
,会简单一点(但也只是一点)。
ZipFile
有一个entries()
方法,可以获取所有的元素。然后遍历整个所有的entries。与ZipInputStream
不同的就是,可以通过entries对象获取单个inputStream
,就不存在自己看分割长度的问题。
具体代码如下:
1 | /*** |
zip4j方式
Zip4j是用于zip文件或流的最全面的Java库。最重要的是:zip4j是唯一一个支持压缩文件加密的工具。像上面提到的ZipOutputStream
并不支持加密。并且zip4j的API很简单。如果不是,一般就不需要封装了,可以直接用。
下面还是给出一个简单的封装,主要是将其功能封装在了多个重载函数中:
1 | /*** |