转自:https://www.cnblogs.com/zeng1994/p/7862288.html
1 package com.guo.utils; 2 3 import java.io.*; 4 import java.util.ArrayList; 5 import java.util.List; 6 import java.util.zip.ZipEntry; 7 import java.util.zip.ZipOutputStream; 8 9 public class ZipUtils { 10 private static final int BUFFER_SIZE = 2 * 1024; 11 12 /** 13 * 压缩成ZIP 方法 * @param srcDir 压缩文件夹路径 14 * @param out 压缩文件输出流 15 * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构; 16 * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) 17 * @throws RuntimeException 压缩失败会抛出运行时异常 18 */ 19 public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure) 20 throws RuntimeException{ 21 22 long start = System.currentTimeMillis(); 23 ZipOutputStream zos = null ; 24 try { 25 zos = new ZipOutputStream(out); 26 File sourceFile = new File(srcDir); 27 compress(sourceFile,zos,sourceFile.getName(),KeepDirStructure); 28 long end = System.currentTimeMillis(); 29 System.out.println("压缩完成,耗时:" + (end - start) +" ms"); 30 } catch (Exception e) { 31 throw new RuntimeException("zip error from ZipUtils",e); 32 }finally{ 33 if(zos != null){ 34 try { 35 zos.close(); 36 } catch (IOException e) { 37 e.printStackTrace(); 38 } 39 } 40 } 41 42 } 43 44 /** 45 * 压缩成ZIP 方法 * @param srcFiles 需要压缩的文件列表 46 * @param out 压缩文件输出流 47 * @throws RuntimeException 压缩失败会抛出运行时异常 48 */ 49 public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException { 50 long start = System.currentTimeMillis(); 51 ZipOutputStream zos = null ; 52 try { 53 zos = new ZipOutputStream(out); 54 for (File srcFile : srcFiles) { 55 byte[] buf = new byte[BUFFER_SIZE]; 56 zos.putNextEntry(new ZipEntry(srcFile.getName())); 57 int len; 58 FileInputStream in = new FileInputStream(srcFile); 59 while ((len = in.read(buf)) != -1){ 60 zos.write(buf, 0, len); 61 } 62 zos.closeEntry(); 63 in.close(); 64 } 65 long end = System.currentTimeMillis(); 66 System.out.println("压缩完成,耗时:" + (end - start) +" ms"); 67 } catch (Exception e) { 68 throw new RuntimeException("zip error from ZipUtils",e); 69 }finally{ 70 if(zos != null){ 71 try { 72 zos.close(); 73 } catch (IOException e) { 74 e.printStackTrace(); 75 } 76 } 77 } 78 } 79 80 81 /** 82 * 递归压缩方法 83 * @param sourceFile 源文件 84 * @param zos zip输出流 85 * @param name 压缩后的名称 86 * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构; 87 * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) 88 * @throws Exception 89 */ 90 private static void compress(File sourceFile, ZipOutputStream zos, String name, 91 boolean KeepDirStructure) throws Exception{ 92 byte[] buf = new byte[BUFFER_SIZE]; 93 if(sourceFile.isFile()){ 94 // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字 95 zos.putNextEntry(new ZipEntry(name)); 96 // copy文件到zip输出流中 97 int len; 98 FileInputStream in = new FileInputStream(sourceFile); 99 while ((len = in.read(buf)) != -1){ 100 zos.write(buf, 0, len); 101 } 102 // Complete the entry 103 zos.closeEntry(); 104 in.close(); 105 } else { 106 //是文件夹 107 File[] listFiles = sourceFile.listFiles(); 108 if(listFiles == null || listFiles.length == 0){ 109 // 需要保留原来的文件结构时,需要对空文件夹进行处理 110 if(KeepDirStructure){ 111 // 空文件夹的处理 112 zos.putNextEntry(new ZipEntry(name + "/")); 113 // 没有文件,不需要文件的copy 114 zos.closeEntry(); 115 } 116 117 }else { 118 for (File file : listFiles) { 119 // 判断是否需要保留原来的文件结构 120 if (KeepDirStructure) { 121 // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠, 122 // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了 123 compress(file, zos, name + "/" + file.getName(),KeepDirStructure); 124 } else { 125 compress(file, zos, file.getName(),KeepDirStructure); 126 } 127 128 } 129 } 130 } 131 } 132 133 public static void main(String[] args) throws Exception { 134 /** 测试压缩方法 */ 135 FileOutputStream fos1= new FileOutputStream(new File("E:/testZip.zip")); 136 ZipUtils.toZip("E:/testZip", fos1,true); 137 138 /** 测试压缩方法 */ 139 List<File> fileList = new ArrayList<>(); 140 fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/jar.exe")); 141 fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/java.exe")); 142 FileOutputStream fos2= new FileOutputStream(new File("c:/mytest02.zip")); 143 ZipUtils.toZip(fileList, fos2); 144 } 145 }
注意点:
- 文件和文件夹的压缩,通过递归的compress方法来实现,从最深的一层开始。
- 如果是文件夹,在传name时,需要在前面带一个“/”。表示是文件夹。
第123行:compress(file, zos, name + "/" + file.getName(),KeepDirStructure);
- 空文件夹要保留,也是通过后面加“/”。
- 压缩包中的文件,通过ZipEntry对象来添加,添加完之后,需要通过流的closeEntry()来关闭。
- web项目中,把response写到返回流中就行。