最近碰到個需要下載zip壓縮包的需求,于是我在網(wǎng)上找了下別人寫好的zip工具類。但找了好多篇博客,總是發(fā)現(xiàn)有bug。因此就自己來寫了個工具類。
這個工具類的功能為:
(1)可以壓縮文件,也可以壓縮文件夾
(2)同時支持壓縮多級文件夾,工具內(nèi)部做了遞歸處理
(3)碰到空的文件夾,也可以壓縮
(4)可以選擇是否保留原來的目錄結(jié)構(gòu),如果不保留,所有文件跑壓縮包根目錄去了,且空文件夾直接舍棄。注意:如果不保留文件原來目錄結(jié)構(gòu),在碰到文件名相同的文件時,會壓縮失敗。
(5)代碼中提供了2個壓縮文件的方法,一個的輸入?yún)?shù)為文件夾路徑,一個為文件列表,可根據(jù)實(shí)際需求選擇方法。
下面直接上代碼
一、代碼
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
package com.tax.core.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * ZipUtils * @author ZENG.XIAO.YAN * @date 2017年11月19日 下午7:16:08 * @version v1.0 */ public class ZipUtils { private static final int BUFFER_SIZE = 2 * 1024 ; /** * 壓縮成ZIP 方法1 * @param srcDir 壓縮文件夾路徑 * @param out 壓縮文件輸出流 * @param KeepDirStructure 是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu); * false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會出現(xiàn)同名文件,會壓縮失敗) * @throws RuntimeException 壓縮失敗會拋出運(yùn)行時異常 */ public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure) throws RuntimeException{ long start = System.currentTimeMillis(); ZipOutputStream zos = null ; try { zos = new ZipOutputStream(out); File sourceFile = new File(srcDir); compress(sourceFile,zos,sourceFile.getName(),KeepDirStructure); long end = System.currentTimeMillis(); System.out.println( "壓縮完成,耗時:" + (end - start) + " ms" ); } catch (Exception e) { throw new RuntimeException( "zip error from ZipUtils" ,e); } finally { if (zos != null ){ try { zos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 壓縮成ZIP 方法2 * @param srcFiles 需要壓縮的文件列表 * @param out 壓縮文件輸出流 * @throws RuntimeException 壓縮失敗會拋出運(yùn)行時異常 */ public static void toZip(List<File> srcFiles , OutputStream out) throws RuntimeException { long start = System.currentTimeMillis(); ZipOutputStream zos = null ; try { zos = new ZipOutputStream(out); 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); } zos.closeEntry(); in.close(); } long end = System.currentTimeMillis(); System.out.println( "壓縮完成,耗時:" + (end - start) + " ms" ); } catch (Exception e) { throw new RuntimeException( "zip error from ZipUtils" ,e); } finally { if (zos != null ){ try { zos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 遞歸壓縮方法 * @param sourceFile 源文件 * @param zos zip輸出流 * @param name 壓縮后的名稱 * @param KeepDirStructure 是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu); * false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會出現(xiàn)同名文件,會壓縮失敗) * @throws Exception */ private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure) throws Exception{ byte [] buf = new byte [BUFFER_SIZE]; if (sourceFile.isFile()){ // 向zip輸出流中添加一個zip實(shí)體,構(gòu)造器中name為zip實(shí)體的文件的名字 zos.putNextEntry( new ZipEntry(name)); // copy文件到zip輸出流中 int len; FileInputStream in = new FileInputStream(sourceFile); while ((len = in.read(buf)) != - 1 ){ zos.write(buf, 0 , len); } // Complete the entry zos.closeEntry(); in.close(); } else { File[] listFiles = sourceFile.listFiles(); if (listFiles == null || listFiles.length == 0 ){ // 需要保留原來的文件結(jié)構(gòu)時,需要對空文件夾進(jìn)行處理 if (KeepDirStructure){ // 空文件夾的處理 zos.putNextEntry( new ZipEntry(name + "/" )); // 沒有文件,不需要文件的copy zos.closeEntry(); } } else { for (File file : listFiles) { // 判斷是否需要保留原來的文件結(jié)構(gòu) if (KeepDirStructure) { // 注意:file.getName()前面需要帶上父文件夾的名字加一斜杠, // 不然最后壓縮包中就不能保留原來的文件結(jié)構(gòu),即:所有文件都跑到壓縮包根目錄下了 compress(file, zos, name + "/" + file.getName(),KeepDirStructure); } else { compress(file, zos, file.getName(),KeepDirStructure); } } } } } public static void main(String[] args) throws Exception { /** 測試壓縮方法1 */ FileOutputStream fos1 = new FileOutputStream( new File( "c:/mytest01.zip" )); ZipUtils.toZip( "D:/log" , fos1, true ); /** 測試壓縮方法2 */ List<File> fileList = new ArrayList<>(); fileList.add( new File( "D:/Java/jdk1.7.0_45_64bit/bin/jar.exe" )); fileList.add( new File( "D:/Java/jdk1.7.0_45_64bit/bin/java.exe" )); FileOutputStream fos2 = new FileOutputStream( new File( "c:/mytest02.zip" )); ZipUtils.toZip(fileList, fos2); } } |
二、注意事項(xiàng)
寫該工具類時,有些注意事項(xiàng)說一下:
(1)支持選擇是否保留原來的文件目錄結(jié)構(gòu),如果不保留,那么空文件夾直接不用處理。
(1)碰到空文件夾時,如果需要保留目錄結(jié)構(gòu),則直接添加個ZipEntry就可以了,不過就是這個entry的名字后面需要帶上一斜杠(/)表示這個是目錄。
(2)遞歸時,不需要把zip輸出流關(guān)閉,zip輸出流的關(guān)閉應(yīng)該是在調(diào)用完遞歸方法后面關(guān)閉
(3)遞歸時,如果是個文件夾且需要保留目錄結(jié)構(gòu),那么在調(diào)用方法壓縮他的子文件時,需要把文件夾的名字加一斜杠給添加到子文件名字前面,這樣壓縮后才有多級目錄。
三、如何在javaWeb項(xiàng)目中使用該工具類
這個工具類在web項(xiàng)目中的使用場景就是多文件下載,我就簡單說個下載多個excel表格的案例吧。
代碼中的步驟為:
(1)創(chuàng)建一個臨時文件夾
(2)將要下載的文件生成至該臨時文件夾內(nèi)
(3)當(dāng)所有文件生成完后,獲取HttpServletResponse獲取設(shè)置下載的header
(4)調(diào)用工具類的方法,傳入上面生成的臨時文件夾路徑及response獲取的輸出流;這樣就下載出來zip包了
(5)遞歸刪除掉上面生成的臨時文件夾和文件
下面為一個示例代碼的代碼片段,不是完整代碼,簡單看一下代碼中的步驟
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
|
if (userList.size() > 0 ){ /** 下面為下載zip壓縮包相關(guān)流程 */ HttpServletRequest request = ServletActionContext.getRequest(); FileWriter writer; /** 1.創(chuàng)建臨時文件夾 */ String rootPath = request.getSession().getServletContext().getRealPath( "/" ); File temDir = new File(rootPath + "/" + UUID.randomUUID().toString().replaceAll( "-" , "" )); if (!temDir.exists()){ temDir.mkdirs(); } /** 2.生成需要下載的文件,存放在臨時文件夾內(nèi) */ // 這里我們直接來10個內(nèi)容相同的文件為例,但這個10個文件名不可以相同 for ( int i = 0 ; i < 10 ; i++) { dataMap.put( "userList" , userList); Map<String, String> endMap = new HashMap<>(); endMap.put( "user" , "老王" ); endMap.put( "time" , "2017-10-10 10:50:55" ); dataMap.put( "endMap" , endMap); Configuration cfg = new Configuration(Configuration.VERSION_2_3_22); cfg.setServletContextForTemplateLoading(ServletActionContext.getServletContext(), "/ftl" ); Template template = cfg.getTemplate( "exportExcel.ftl" ); writer = new FileWriter(temDir.getPath()+ "/excel" + i + ".xls" ); template.process(dataMap, writer); writer.flush(); writer.close(); } /** 3.設(shè)置response的header */ HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType( "application/zip" ); response.setHeader( "Content-Disposition" , "attachment; filename=excel.zip" ); /** 4.調(diào)用工具類,下載zip壓縮包 */ // 這里我們不需要保留目錄結(jié)構(gòu) ZipUtils.toZip(temDir.getPath(), response.getOutputStream(), false ); /** 5.刪除臨時文件和文件夾 */ // 這里我沒寫遞歸,直接就這樣刪除了 File[] listFiles = temDir.listFiles(); for ( int i = 0 ; i < listFiles.length; i++) { listFiles[i].delete(); } temDir.delete(); } |
到此這篇關(guān)于Java實(shí)現(xiàn)將文件或者文件夾壓縮成zip的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)將文件或者文件夾壓縮成zip內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/zeng1994/p/7862288.html