轉自: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寫到返回流中就行。
