1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.nuiton.util;
24
25 import org.apache.commons.io.FileUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import java.io.BufferedInputStream;
30 import java.io.BufferedOutputStream;
31 import java.io.File;
32 import java.io.FileFilter;
33 import java.io.FileInputStream;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.nio.charset.Charset;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.Enumeration;
42 import java.util.List;
43 import java.util.zip.ZipEntry;
44 import java.util.zip.ZipFile;
45 import java.util.zip.ZipInputStream;
46 import java.util.zip.ZipOutputStream;
47
48
49
50
51
52
53
54
55
56
57 public class ZipUtil {
58
59
60 private static final Log log = LogFactory.getLog(ZipUtil.class);
61
62
63 private static final int BUFFER_SIZE = 8 * 1024;
64
65
66 private static final String LOCAL_SEP = File.separator;
67
68 private static final String LOCAL_SEP_PATTERN = "\\".equals(LOCAL_SEP) ?
69 LOCAL_SEP + LOCAL_SEP : LOCAL_SEP;
70
71
72 private static final String ZIP_SEP = "/";
73
74 private static final String ZIP_SEP_PATTERN = "/";
75
76
77 protected static FileFilter ALL_FILE_FILTER = new FileFilter() {
78 public boolean accept(File pathname) {
79 return true;
80 }
81 };
82
83
84
85
86
87
88
89
90
91 public static String uncompress(File file, File targetDir) throws IOException {
92 String result;
93 result = uncompressAndRename(file, targetDir, null, null);
94 return result;
95 }
96
97
98
99
100
101
102
103
104
105
106
107 public static String uncompress(InputStream stream, File targetDir) throws IOException {
108 String result = uncompressAndRename(stream, targetDir, null, null);
109 return result;
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public static String uncompressAndRename(File file,
128 File targetDir,
129 String renameFrom,
130 String renameTo) throws IOException {
131 return uncompressAndRename(new FileInputStream(file), targetDir, renameFrom, renameTo);
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 public static String uncompressAndRename(InputStream stream,
152 File targetDir,
153 String renameFrom,
154 String renameTo) throws IOException {
155 String result = "";
156 ZipInputStream in = new ZipInputStream(new BufferedInputStream(stream));
157 try {
158 ZipEntry entry;
159 while ((entry = in.getNextEntry()) != null) {
160 String name = entry.getName();
161 if (renameFrom != null && renameTo != null) {
162 name = name.replaceAll(renameFrom, renameTo);
163 if (log.isDebugEnabled()) {
164 log.debug("rename " + entry.getName() + " → " + name);
165 }
166 }
167 result = name;
168 File target = new File(targetDir, name);
169 if (entry.isDirectory()) {
170 FileUtil.createDirectoryIfNecessary(target);
171 } else {
172 FileUtil.createDirectoryIfNecessary(target.getParentFile());
173 OutputStream out = new BufferedOutputStream(new FileOutputStream(target));
174 try {
175 byte[] buffer = new byte[BUFFER_SIZE];
176 int len;
177 while ((len = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
178 out.write(buffer, 0, len);
179 }
180 } finally {
181 out.close();
182 }
183 }
184 }
185 } finally {
186 in.close();
187 }
188 return result;
189 }
190
191
192
193
194
195
196
197
198
199
200
201 public static void compressFiles(File zipFile,
202 File root,
203 Collection<File> includes) throws
204 IOException {
205 compressFiles(zipFile, root, includes, false);
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219 public static void compressFiles(File zipFile,
220 File root,
221 Collection<File> includes,
222 boolean createMD5) throws IOException {
223 OutputStream oStream = new FileOutputStream(zipFile);
224
225
226 if (createMD5) {
227 oStream = new MD5OutputStream(oStream);
228 }
229 try {
230 ZipOutputStream zipOStream = new ZipOutputStream(oStream);
231
232 for (File file : includes) {
233 String entryName = toZipEntryName(root, file);
234
235
236 ZipEntry entry = new ZipEntry(entryName);
237 entry.setTime(file.lastModified());
238 zipOStream.putNextEntry(entry);
239
240 if (file.isFile() && file.canRead()) {
241 byte[] readBuffer = new byte[BUFFER_SIZE];
242 int bytesIn;
243 BufferedInputStream bis = new BufferedInputStream(
244 new FileInputStream(file), BUFFER_SIZE);
245 try {
246 while ((bytesIn =
247 bis.read(readBuffer, 0, BUFFER_SIZE)) != -1) {
248 zipOStream.write(readBuffer, 0, bytesIn);
249 }
250 } finally {
251 bis.close();
252 }
253 }
254 zipOStream.closeEntry();
255 }
256 zipOStream.close();
257
258
259 if (createMD5) {
260 String md5hash = StringUtil.asHex(((MD5OutputStream) oStream).hash());
261 File md5File = new File(zipFile.getAbsoluteFile() + ".md5");
262 FileUtils.write(md5File, md5hash, Charset.defaultCharset());
263 }
264 } finally {
265 oStream.close();
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 public static void compress(File zipFile,
281 File fileOrDirectory) throws IOException {
282 compress(zipFile, fileOrDirectory, null, false);
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297 public static void compress(File zipFile,
298 File fileOrDirectory,
299 FileFilter filter) throws IOException {
300 compress(zipFile, fileOrDirectory, filter, false);
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 public static void compress(File zipFile,
317 File fileOrDirectory,
318 FileFilter filter,
319 boolean createMD5) throws IOException {
320 if (filter == null) {
321 filter = ALL_FILE_FILTER;
322 }
323 List<File> files = new ArrayList<File>();
324 if (fileOrDirectory.isDirectory()) {
325 files = FileUtil.getFilteredElements(fileOrDirectory, filter, true);
326 } else if (filter.accept(fileOrDirectory)) {
327 files.add(fileOrDirectory);
328 }
329
330 compressFiles(zipFile, fileOrDirectory.getParentFile(), files,
331 createMD5);
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345 private static String toZipEntryName(File root, File file) {
346 String result = file.getPath();
347
348 if (root != null) {
349 String rootPath = root.getPath();
350 if (result.startsWith(rootPath)) {
351 result = result.substring(rootPath.length());
352 }
353 }
354
355 result = result.replace('\\', '/');
356 if (file.isDirectory()) {
357 result += '/';
358 }
359 while (result.startsWith("/")) {
360 result = result.substring(1);
361 }
362 return result;
363 }
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389 public static void scan(File zipFile,
390 File targetDir,
391 List<String> newFiles,
392 List<String> existingFiles,
393 FileFilter excludeFilter,
394 String renameFrom,
395 String renameTo) throws IOException {
396 ZipFile zip = null;
397 try {
398 zip = new ZipFile(zipFile);
399 boolean findExisting = targetDir != null && targetDir.exists();
400 boolean filter = findExisting && excludeFilter != null;
401 boolean rename = renameFrom != null && renameTo != null;
402 Enumeration<? extends ZipEntry> entries = zip.entries();
403 while (entries.hasMoreElements()) {
404 String entryName = entries.nextElement().getName();
405 if (rename) {
406 entryName = entryName.replaceAll(renameFrom, renameTo);
407 }
408 String name = convertToLocalEntryName(entryName);
409 if (findExisting || filter) {
410 File file = new File(targetDir, name);
411 if (filter && excludeFilter.accept(file)) continue;
412 if (file.exists()) {
413 existingFiles.add(name);
414 continue;
415 }
416 }
417 newFiles.add(name);
418 }
419 } finally {
420 if (zip != null) {
421 zip.close();
422 }
423 }
424 }
425
426 @SuppressWarnings({"unchecked"})
427 public static List<String>[] scanAndExplodeZip(File source,
428 File root,
429 FileFilter excludeFilter)
430 throws IOException {
431
432 List<String> overwrittenFiles = new ArrayList<String>();
433 List<String> newFiles = new ArrayList<String>();
434
435
436 scan(source, root, newFiles, overwrittenFiles, excludeFilter, null,
437 null);
438
439 return new List[]{newFiles, overwrittenFiles};
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458 public static String uncompress(File file,
459 File targetDir,
460 List<String> toTreate,
461 String renameFrom,
462 String renameTo) throws IOException {
463 if (toTreate == null || toTreate.isEmpty()) {
464 return uncompressAndRename(file, targetDir, renameFrom, renameTo);
465 }
466
467 boolean rename = renameFrom != null && renameTo != null;
468
469 String result = "";
470 ZipEntry entry;
471 ZipInputStream in = new ZipInputStream(new FileInputStream(file));
472 try {
473 while ((entry = in.getNextEntry()) != null) {
474 String name = entry.getName();
475 if (rename) {
476 result = convertToLocalEntryName(name.replaceAll(renameFrom,
477 renameTo));
478 } else {
479 result = convertToLocalEntryName(name);
480 }
481
482 if (log.isDebugEnabled()) {
483 log.debug("open [" + name + "] : " + result);
484 }
485 if (!toTreate.contains(result)) {
486 continue;
487 }
488
489 if (log.isDebugEnabled()) {
490 log.debug("copy [" + name + "] : " + result);
491 }
492 File target = new File(targetDir, result);
493 if (entry.isDirectory()) {
494 FileUtil.createDirectoryIfNecessary(target);
495 } else {
496 FileUtil.createDirectoryIfNecessary(target.getParentFile());
497 OutputStream out = new BufferedOutputStream(
498 new FileOutputStream(target));
499 try {
500 byte[] buffer = new byte[BUFFER_SIZE];
501 int len;
502 while ((len = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
503 out.write(buffer, 0, len);
504 }
505 } finally {
506 out.close();
507 }
508 }
509 }
510 } finally {
511 in.close();
512 }
513 return result;
514 }
515
516
517
518
519
520
521
522
523
524 public static void uncompressFiltred(File file,
525 File targetDir,
526 String... excludes) throws IOException {
527
528 ZipFile zipFile = new ZipFile(file);
529
530 Enumeration<? extends ZipEntry> entries = zipFile.entries();
531
532 while (entries.hasMoreElements()) {
533 ZipEntry entry = entries.nextElement();
534
535 String name = entry.getName();
536
537 boolean excludeEntry = false;
538 if (excludes != null) {
539 for (String exclude : excludes) {
540 if (name.matches(exclude)) {
541 excludeEntry = true;
542 }
543 }
544 }
545
546 if (!excludeEntry) {
547 File target = new File(targetDir, name);
548 if (entry.isDirectory()) {
549 FileUtil.createDirectoryIfNecessary(target);
550 } else {
551
552 FileUtil.createDirectoryIfNecessary(target.getParentFile());
553 InputStream in = zipFile.getInputStream(entry);
554 try {
555 OutputStream out = new BufferedOutputStream(
556 new FileOutputStream(target));
557 try {
558 byte[] buffer = new byte[8 * 1024];
559 int len;
560
561 while ((len = in.read(buffer, 0, 8 * 1024)) != -1) {
562 out.write(buffer, 0, len);
563 }
564 } finally {
565 out.close();
566 }
567 } finally {
568 in.close();
569 }
570 }
571 }
572 }
573 }
574
575
576
577
578
579
580
581
582
583 public static boolean isZipFile(File file) {
584
585 boolean result = false;
586 try {
587 ZipFile zipFile = new ZipFile(file);
588 zipFile.close();
589 result = true;
590 } catch (IOException e) {
591
592 }
593 return result;
594 }
595
596 protected static String convertToLocalEntryName(String txt) {
597 String s = txt.replaceAll(ZIP_SEP_PATTERN, LOCAL_SEP_PATTERN);
598 if (s.endsWith(ZIP_SEP)) {
599 s = s.substring(0, s.length() - 1);
600 }
601 return s;
602 }
603 }