最近複習到IO,想找個案例作一作,剛好下載了許多圖片壓縮包,查看圖片很不方便,因此打算用IO把圖片都解壓到同一個文件夾下。而後集中打包。java
本例使用jdk自帶的ZipInputStream和ZipOutPutStream,功能有限不支持rar可是api很簡單。windows
import java.io.*; import java.util.zip.*; /** * Created by tm on 2017/2/18. * time : 17:33 * project_name : toolSite * 提供zip文件和文件夾的解壓和壓縮功能。 */ public class ZipTool { /** * 壓縮單個文件 * 此處傳參都是絕對路徑。 * @param src 源文件絕對路徑名 * @param destPath 將生成的壓縮包絕對路徑(路徑以/結尾) * @param destName 將生成的壓縮包文件名 * @throws IOException */ public static void compressFile(String src, String destPath,String destName) throws IOException { File f = new File(src); if (!f.exists()) { throw new RuntimeException("file not find "); } File folder = new File(destPath); if(!folder.exists()){ folder.mkdir(); } InputStream is = new FileInputStream(f); BufferedInputStream buffIn = new BufferedInputStream(is); //建立文件File,建立文件輸出流,包裝到Zip文件輸出處理流上,最後把Zip處理流再包裝到Buffer緩衝輸出流中。 ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(destPath+destName))); BufferedOutputStream buffOut = new BufferedOutputStream(zos); //須要將文件項put到entry中,解壓文件時今後entry中獲取數據。 zos.putNextEntry(new ZipEntry(f.getName())); //b是指the next byte of data int b; while ((b = buffIn.read()) != -1) { buffOut.write(b); } buffIn.close(); buffOut.flush(); buffOut.close(); } /** * 解壓單個zip文件(上面壓縮後的解壓,認爲不包含子文件夾) * @param src 源zip的絕對路徑 * @param dest 解壓的目標文件夾(路徑以/結尾) * @throws IOException */ public static void unCompress(String src, String dest) throws IOException { File file = new File(src); if(!file.exists()){ throw new RuntimeException("zip file not found"); } File d = new File(dest); if(!d.exists()){ d.mkdir(); } InputStream is = new FileInputStream(file); ZipInputStream zis = new ZipInputStream(is); ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { //解壓文件須要從zip中讀取每個entry,一個一個地outPut出來 OutputStream out = new FileOutputStream(new File(dest + entry.getName())); BufferedOutputStream bos = new BufferedOutputStream(out); BufferedInputStream buffIn = new BufferedInputStream(new ZipFile(file).getInputStream(entry)); int b; while ((b = buffIn.read()) != -1) { bos.write(b); } bos.flush(); buffIn.close(); bos.close(); } zis.close(); } /** * 壓縮指定的文件夾(代碼裏沒有對路徑作校驗,讀者可自行添加,參考上例) * @param srcFolder 源文件夾 * @param destFileName 目標文件名 * @throws IOException */ public static void compressNestFolder(String srcFolder, String destFileName) throws IOException { System.out.println(">>>>>>>>>>開始壓縮"); File folder = new File(srcFolder); if (!folder.exists()) { throw new RuntimeException("folder not find Exception"); } OutputStream os = new FileOutputStream(new File(destFileName)); ZipOutputStream zos = new ZipOutputStream(os); BufferedOutputStream bo = new BufferedOutputStream(zos); zipFileOrFolder(zos, bo, "", folder); zos.close(); bo.close(); System.out.println("壓縮完成>>>>>>>>>>"); } /** * 將目錄下全部的文件和子文件都壓縮到zos中 * @param zos * @param bo * @param src * @param f * @throws IOException */ private static void zipFileOrFolder(ZipOutputStream zos, BufferedOutputStream bo, String src, File f) throws IOException { File[] files; if (f.isDirectory()) { files = f.listFiles(); assert files != null; System.out.println("========== " + f.getName());
//添加文件夾的entry,不添加的話,解壓時會出問題。 zos.putNextEntry(new ZipEntry( src+f.getName()+"/" )); System.out.println( src+f.getName()+"/" ); src = src+f.getName() + "/"; for (File f1 : files) {
//使用了遞歸調用獲取下一層文件夾並壓縮 zipFileOrFolder(zos, bo, src, f1); } } else { System.out.println("---------- " + f.getName()); InputStream in = new FileInputStream(f); BufferedInputStream bi = new BufferedInputStream(in); zos.putNextEntry(new ZipEntry( src+f.getName() )); int b; while ((b = bi.read()) != -1) { bo.write(b); } bo.flush(); bi.close(); zos.closeEntry(); } } /** * 解壓單個zip文件,保留文件夾層級關係 * @param zipFile * @param outPath * @throws IOException */ public static void unZip(String zipFile, String outPath) throws IOException { File zip = new File(zipFile); ZipFile zf = new ZipFile(zip); InputStream is = new FileInputStream(zipFile); ZipInputStream zis = new ZipInputStream(is); ZipEntry e; File out = new File(outPath); if (!out.exists()) { out.mkdir(); } while ((e = zis.getNextEntry()) != null) { System.out.println(e.isDirectory()); File f = new File(outPath + e.getName()); System.out.println(f.getAbsolutePath()); if(e.isDirectory()){ f.mkdir();continue; } OutputStream os = new FileOutputStream(f); BufferedOutputStream bos = new BufferedOutputStream(os); BufferedInputStream bis = new BufferedInputStream(zf.getInputStream(e)); int b; while ((b = bis.read()) != -1) { bos.write(b); } bos.flush(); bos.close(); bis.close(); } zis.close(); } public static void unZipAll(String zipFolder,String destFolder){ //todo } public static void main(String[] args) throws IOException { compressFile("D:/test/123.txt", "D:/test/a/b/", "123.zip"); unCompress("D:/test/123.zip", "D:/test/"); compressNestFolder("D:/test/測試zip/新垣結衣/", "D:/test/測試zip/新垣結衣1.zip"); unZip("D:/test/測試zip/新垣結衣1.zip", "D:/test/測試zip/"); } }
後記:api
1.添加到zip中使用putNextEntry,從zip中讀取時須要建立一個ZipFile而後從entry中獲取InputStream。測試
2.須要特別注意壓縮文件時的Entry存放次序,在添加entry時務必先添加文件夾的entry。由於取entry時,若是亂序就會找不到文件。好比獲取/bt/123.pic時,由於沒有實現建立父目錄/bt,致使寫文件時找不到文件。spa
3.對entry.isDirectory()的判斷,api中是根據name是否以 / 結尾的。所以存放folder時,也要使用 / 做爲路徑分割符。java在windows平臺上是支持 / 的,雖然windows平臺上路徑分隔符是 \ (java中是\\)。建議仍是用 / 吧。對象
4.Zip對象存放文件是使用相對路徑的,因此壓縮什麼的不要有盤符。添加目錄時以 / 結尾,多級目錄時添加文件使用徹底相對路徑名 /相對路徑1/相對路徑2/文件名,能夠經過查看打印信息瞭解方法執行過程。blog
-----------------以上-----------------遞歸