Java解压缩zip

前言

java解压缩工具类,主流有两种方式。

  • java自带,不只是中文
  • Apache提供的ant jar,支持中文

其实两者的api的使用形式基本是一样的。这里直接贴出两个代码。也可以在github中查看

Java原生的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.document.zip;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
* 利用java原生的类,来实现zip的解压缩工具类
* 需要注意的是java原生的不支持中文名
* @author: zl
* @Date: 2019/12/8 16:28
*/
@Slf4j
public class ZipUtil {

/**
* 缓冲大小
*/
private static int BUFFER_SIZE = 2 << 10;

/**
* 是否保留原来的目录结构
* true: 保留目录结构;
* false: 所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
*/
private static final boolean KeepDirStructure = true;

/**
* 压缩文件
* @param srcDir 源文件路径
* @param outPathFile 输出路径(带文件名)
* @param isDelSrcFile 解压后 是否删除源路径文件
* @throws RuntimeException
*/
public static void toZip(String srcDir, String outPathFile, boolean isDelSrcFile) {
long start = System.currentTimeMillis();
File sourceFile = new File(srcDir);
if(!sourceFile.exists()){
throw new RuntimeException("需压缩文件或者文件夹不存在");
}
FileOutputStream out = null;
ZipOutputStream zos = null;
try {
out = new FileOutputStream(new File(outPathFile));
zos = new ZipOutputStream(out);
compress(sourceFile, zos, sourceFile.getName());
if(isDelSrcFile){
sourceFile.delete();
}
log.info("原文件:{}. 压缩到:{}完成. 是否删除原文件:{}. 耗时:{}ms. ",srcDir,outPathFile,isDelSrcFile,
System.currentTimeMillis()-start);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (zos != null) zos.close();
if (out != null) out.close();
} catch (Exception e) {}
}
}

/**
* 递归压缩方法
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
*/
private static void compress(File sourceFile, ZipOutputStream zos, String name)
throws IOException {
byte[] buf = new byte[BUFFER_SIZE];
if (sourceFile.isFile()) {
zos.putNextEntry(new ZipEntry(name));
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
} else {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
if (KeepDirStructure) {
zos.putNextEntry(new ZipEntry(name + "/"));
zos.closeEntry();
}
} else {
for (File file : listFiles) {
if (KeepDirStructure) {
compress(file, zos, name + "/" + file.getName());
} else {
compress(file, zos, file.getName());
}
}
}
}
}

/**
* zip解压
* @param srcFile zip源文件
* @param destDirPath 解压后的目标文件夹
* @throws RuntimeException 解压失败会抛出运行时异常,也可以自定义异常
*/
public static void unZip(File srcFile, String destDirPath) {
long start = System.currentTimeMillis();
// 判断源文件是否存在
if (!srcFile.exists()) {
throw new RuntimeException("zip源文件不存在!");
}
File descFile = new File(destDirPath);
if(!descFile.exists()) descFile.mkdirs();
// 开始解压
ZipFile zipFile = null;
InputStream is = null;
FileOutputStream fos = null;
try {
zipFile = new ZipFile(srcFile, Charset.forName("GBK"));
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
log.info("解压 {}",entry.getName());
if (entry.isDirectory()) { // 目录
String dirPath = destDirPath + "/" + entry.getName();
File dir = new File(dirPath);
dir.mkdirs();
} else { // 文件
File targetFile = new File(destDirPath + "/" + entry.getName());
if(!targetFile.getParentFile().exists()){
targetFile.getParentFile().mkdirs();
}
targetFile.createNewFile();
// 将压缩文件内容写入到这个文件中
is = zipFile.getInputStream(entry);
fos = new FileOutputStream(targetFile);
int len;
byte[] buf = new byte[BUFFER_SIZE];
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
// 关流顺序,先打开的后关闭
fos.close();
is.close();
}
}
long end = System.currentTimeMillis();
log.info("解压完成,耗时:{} ms",end - start);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(fos != null) fos.close();
if(is != null) is.close();
if(zipFile != null) zipFile.close();
} catch (IOException e) {
// do nothing
}
}
}
}

Apache ant jar

这里使用的jar包为1.9.7,其他版本没有测试过

1
2
3
4
5
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.7</version>
</dependency>

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package com.document.zip;

import lombok.extern.slf4j.Slf4j;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;
import java.util.Enumeration;
import java.util.List;

/**
* 利用Apache Ant的jar包来解压缩zip工具类。
* 相对于java原生的技术,可以支持中文
* @author: zl
* @Date: 2019/12/8 16:29
*/
@Slf4j
public class AntZipUtil {

/**
* 缓冲大小
*/
private static int BUFFER_SIZE = 2 << 10;

public static void toZip(String srcDir, String zipPath, boolean isDelSrcFile) {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
File sourceFile = new File(srcDir);
File zipFile = new File(zipPath);
if(!sourceFile.exists()){
throw new RuntimeException("需压缩文件或者文件夹不存在");
}
try {
zos = new ZipOutputStream(zipFile);
compress(sourceFile, zos, sourceFile.getName());
if(isDelSrcFile){
sourceFile.delete();
}
log.info("原文件:{}. 压缩到:{}完成. 是否删除原文件:{}. 耗时:{}ms. ",srcDir,zipPath,isDelSrcFile, System.currentTimeMillis()-start);
} catch (IOException e) {
log.error("zip error from AntZipUtil: {}. ",e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (zos != null) {zos.finish();zos.close();}
} catch (Exception e) {}
}
}


/**
* 递归压缩方法
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
*/
private static void compress(File sourceFile, ZipOutputStream zos, String name) throws IOException {
if (sourceFile.isFile()) {
byte[] buf = new byte[BUFFER_SIZE];
zos.putNextEntry(new ZipEntry(sourceFile,name));
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
} else {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
zos.putNextEntry(new ZipEntry(sourceFile,name + "/"));
zos.closeEntry();
} else {
for (File file : listFiles) {
compress(file, zos, name + "/" + file.getName());
}
}
}
}


/**
* 将多个文件压缩成zip,文件放在zip根目录,注意文件名相同会覆盖
* @param srcFiles 需要压缩的文件列表
* @param zipPath zip文件路径
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(List<File> srcFiles , String zipPath) {
long start = System.currentTimeMillis();
File zipFile = new File(zipPath);
File parentFile = zipFile.getParentFile();
if(!parentFile.exists()) parentFile.mkdirs();
FileOutputStream fos = null;
ZipOutputStream zos = null;
try {
fos = new FileOutputStream(zipPath);
zos = new ZipOutputStream(new BufferedOutputStream(fos));
for (File srcFile : srcFiles) {
byte[] buf = new byte[BUFFER_SIZE];
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = in.read(buf)) != -1){
zos.write(buf, 0, len);
}
in.close();
zos.closeEntry();
}
long end = System.currentTimeMillis();
log.info("压缩完成,耗时:" + (end - start) +" ms");
} catch (IOException e) {
throw new RuntimeException(e);
}finally{
try {
if(zos != null){
zos.finish();
zos.close();
}
if(fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}



/**
* 把zip文件解压到指定的文件夹
* @param sourceFile zip文件, 如 "D:/test/aa.zip"
* @param saveFileDir 解压后的文件存放路径, 如"D:/test/" ()
*/
public static void unZip(File sourceFile, String saveFileDir) {
long start = System.currentTimeMillis();
// 判断源文件是否存在
if (!sourceFile.exists())
throw new RuntimeException("zip源文件不存在!");
File dir = new File(saveFileDir);
if(!dir.exists()){
dir.mkdirs();
}
File entryFile;
ZipFile zipFile = null;
InputStream inputStream = null;
try {
zipFile = new ZipFile(sourceFile);
for(Enumeration<ZipEntry> entries = zipFile.getEntries();
entries.hasMoreElements();){
ZipEntry zipEntry = entries.nextElement();
entryFile = new File(saveFileDir + "/" + zipEntry.getName());
if(zipEntry.isDirectory()){
entryFile.mkdirs();
} else {
File parent = entryFile.getParentFile();
if(parent!=null && !parent.exists()){
parent.mkdirs();
}
OutputStream os = new BufferedOutputStream(new FileOutputStream(
entryFile));
byte[] buffer = new byte[BUFFER_SIZE];
int len;
inputStream = zipFile.getInputStream(zipEntry);
while((len = inputStream.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
inputStream.close();
os.close();
}
}
long end = System.currentTimeMillis();
log.info("解压完成,耗时:{} ms",end - start);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(inputStream != null) inputStream.close();
if(zipFile != null) zipFile.close();
} catch (IOException e) {
// nothing
}
}
}
}