package com.cn;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.util.Enumeration;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;import java.util.zip.ZipOutputStream;//錯誤小結://1 關於file.isFile()與file.isDirectory()記憶出了偏差.// 錯誤以為若是Directory一定是file,file不一定是Directory// 更正:file和Directory是兩碼事.只能是file或Directory中其中一個.//2 並不是說我們執行一句File f=new File("F:\\x.txt");// 在本地硬碟上就產生了一個x.txt檔案.而應該進行如下的// 操作才可以.// File f=new File("F:\\x.txt");// if (!f.exists()) {// f.createNewFile();// }// 其中f.createNewFile()表示建立了一個空檔案//// 多數的情況下,我們執行了File f=new File("F:\\x.txt")// 以後再利用輸入資料流,輸出資料流對f進行操作,比如往該x.txt檔案中// 寫入hello world// //3 血的教訓:// zip()方法中沒有關閉流zos.導致壓縮後的檔案解壓時出錯//重要總結://1 關於zip和unzip的核心操作對象是每一個檔案!!!// 比如碰到一個directory,那麼會去遍曆裡面的每一個檔案,挨個對其進行壓縮.// 不要錯誤地理解,若是一個directory,那麼會將其作為一個整體進行壓縮.//2 在JAVA中每一個壓縮檔都用一個ZipEntry表示// 所以在壓縮的過程中要得到每個檔案的完整路徑(從最外層檔案夾至檔案本身)// 用此完整路徑為每個壓縮檔new()一個ZipEntry//3 所以利用zipEntry可記錄原來的目錄層次.解壓後才保持原樣// 也可以看到在解壓時利用entrys.hasMoreElements()來挨個// 解壓每個zipEntry.// 參見解壓中的代碼:// perUnzipFilePath = unzipPath + zipEntry.getName();public class TestZipAndUnZip { public static void main(String[] args) throws Exception { TestZipAndUnZip test=new TestZipAndUnZip(); //壓縮和解壓單個檔案 test.zip2("F:\\kk\\cc.txt","F:\\11.zip"); test.unZipFile2("F:\\11.zip", "F:\\test11"); //壓縮和解壓一個目錄 test.zip2("F:\\kk","F:\\22.zip"); test.unZipFile2("F:\\22.zip", "F:\\test22"); }/** * 該方法將一個給定路徑的檔案壓縮 * @param willZipPath 待壓縮檔的路徑 * @param zipedPath 該檔案壓縮後的路徑 */public void zip2(String willZipPath, String zipedPath) {try {File willZipFile = new File(willZipPath);File zipedFile = new File(zipedPath);ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipedFile));if (willZipFile.isFile()) {fileToZip2(willZipPath, zos);}if (willZipFile.isDirectory()) {dirToZip2(willZipPath, willZipFile, zos);}// 方法調用完成後關閉流zos.close();} catch (Exception e) {}}/** * @param willZipFilePath 待壓縮檔的路徑 * @param zos 壓縮檔輸出資料流 * 1 關於以下兩句代碼 * ZipEntry entry = new ZipEntry(); * zos.putNextEntry(entry); * 把產生的ZipEntry對象加入到壓縮檔中 * 之後往壓縮檔中寫入的內容均放在該ZipEntry對象中 * * 2 fis.close()但是不能在此處zos.close() * 因為該zos是上一方法傳遞過來的.可能在壓縮目錄的時候會 * 再次使用到該zos流.若此時關閉,則導致目錄中的一個檔案 * 被壓縮 */public void fileToZip2(String willZipFilePath,ZipOutputStream zos){try {File willZipFile=new File(willZipFilePath);ZipEntry entry = new ZipEntry(getEntryName2(willZipFilePath, willZipFile));zos.putNextEntry(entry);FileInputStream fis = new FileInputStream(willZipFilePath);int len = 0;while ((len = fis.read()) != -1){zos.write(len);}fis.close();//流關閉錯誤!//zos.close();} catch (Exception e) {}}/** * @param willZipDirctoryPath 原目錄所在路徑 * @param willZipedDirectory 原目錄 * @param zos 壓縮流 * 注意: * 在處理空檔案夾的時候 * getEntryName2(willZipDirctoryPath, willZipedDirectory)+"/" * 中的"/"是必不可少的 */public void dirToZip2(String willZipDirctoryPath,File willZipedDirectory, ZipOutputStream zos) {if (willZipedDirectory.isDirectory()) {File[] files = willZipedDirectory.listFiles();//處理空檔案夾的情況 if (files.length==0) {ZipEntry zipEntry=new ZipEntry(getEntryName2(willZipDirctoryPath, willZipedDirectory)+"/");try {zos.putNextEntry(zipEntry);} catch (Exception e) {e.printStackTrace();}return;} for (int i = 0; i < files.length; i++) {File file = files[i];//若是檔案,遞迴調用fileToZip()if (file.isFile()) {fileToZip2(file.getAbsolutePath(), zos);}//若是檔案,遞迴調用dirToZip()if (file.isDirectory()) {dirToZip2(file.getAbsolutePath(),file, zos);}}}}/** * @param rawPath 需要壓縮的目錄或者檔案的完整路徑 * @param file 需要壓縮的檔案或者目錄 * @return entryName * * 該方法返回EntryName,表示從最外層目錄開始到該檔案(目錄) * 的完整路徑 * 備忘: * 1 該樣本中檔案均存放在某盤下,如E:\所以rawPath.substring(3); * 2 注釋中"@param file 需要壓縮的檔案或者目錄".其實絕大多數情況下 * 都是檔案,只有一種情況是目錄,就是空檔案夾的情況. */public String getEntryName2(String rawPath,File file){try {String rawDir=rawPath.substring(3);int rawDirIndex=file.getAbsolutePath().indexOf(rawDir);String entryName=file.getAbsolutePath().substring(rawDirIndex);return entryName;} catch (Exception e) {}return null;}/** * @param zipedFilePath 原壓縮檔的路徑 * @param unzipPath 檔案解壓後的路徑 * 對於檔案或者目錄操作的小梳理: * 1 對於目錄應該先執行file.mkdir(s)()才可以 * 往裡面其下存入檔案.比如: * File f=new File("F:\\test\\x.txt");if (!f.exists()) {f.createNewFile();}這當然要報錯,因為x.txt的所在目錄還不存在!!所以應該改正為:File f=new File("F:\\test\\x.txt");f.getParentFile().mkdirs();if (!f.exists()) {f.createNewFile();}2同樣的道理File f=new File("F:\\test\\x.txt");if (f.isFile()) {System.out.println("true");}else{System.out.println("false");}結果為false3類似的問題File f=new File("F:\\x.txt");if (f.isFile()) {System.out.println("true");}else{System.out.println("false");}結果為false因為只是new了一個File,並沒有建立!!!File f=new File("F:\\x.txt");f.createNewFile();if (f.isFile()) {System.out.println("true");}else{System.out.println("false");}此時為true此處:if (zipEntry.isDirectory()) { new File(perUnzipFilePath).mkdirs();} else {new File(perUnzipFilePath).getParentFile().mkdirs();}已經建立了每個檔案夾.然後才開始對每個空檔案夾和每個檔案進行流操作.和上面的道理一致,剛開始犯了個錯誤,沒有採用else {fos = new FileOutputStream(perUnzipFile);is = zipFile.getInputStream(zipEntry);while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}}而是用if(perUnzipFile.isFile()){}來操作,這當然錯了.因為該perUnzipFile沒有執行perUnzipFile.createNewFile();所以它還不是File.類似的情況,多採用流操作來進行讀寫.所以總結兩種與File有關的操作:1 File f=new File(""); f.createNewFile(); 然後對f操作2 file f=new File(""); 然後用輸入輸出資料流進行流操作 舉例子: File f=new File("F:\\2221x.txt"); FileOutputStream fos=new FileOutputStream(f); String string="hello"; byte []b=string.getBytes(); fos.write(b, 0, b.length); 該例子是正確的. 疑問:沒有執行 f.createNewFile()為什麼不報錯.因為輸出資料流 FileOutputStream已經幫我們做了該工作了.修改例子即可知:File f=new File("F:\\2221x.txt");if (f.isFile()) {System.out.println("true1");} else {System.out.println("false1");}FileOutputStream fos=new FileOutputStream(f);if (f.isFile()) {System.out.println("true2");} else {System.out.println("false2");}String string="hello";byte []b=string.getBytes();fos.write(b, 0, b.length);輸出false1,true2這就得到了驗證. */public void unZipFile2(String zipedFilePath, String unzipPath) {FileOutputStream fos=null;InputStream is=null;ZipEntry zipEntry=null;String perUnzipFilePath=null;if (!unzipPath.endsWith(File.separator)) {unzipPath+=File.separator;}try {ZipFile zipFile=new ZipFile(zipedFilePath);Enumeration entries=zipFile.entries();byte [] buffer=new byte[1024*8];int len=0;while (entries.hasMoreElements()) {zipEntry = (ZipEntry) entries.nextElement();perUnzipFilePath = unzipPath + zipEntry.getName();//1建立每個檔案夾if (zipEntry.isDirectory()) {//處理空檔案夾的情況//建立空目錄new File(perUnzipFilePath).mkdirs();} else {//為每個檔案創立其所在目錄new File(perUnzipFilePath).getParentFile().mkdirs();} //2在用流操作處理每個檔案夾中的檔案// 2.1if中的操作只是針對空目錄而進行的.所以if中的代碼可以// 注釋掉,無實際意義.// 2.2else中的操作是對於每個具體的檔案而進行的流操作File perUnzipFile = new File(perUnzipFilePath);if (perUnzipFile.isDirectory()) {File[] files = perUnzipFile.listFiles();for (int i = 0; i < files.length; i++) {File file = files[i];fos = new FileOutputStream(file);is = zipFile.getInputStream(zipEntry);while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}}} else {fos = new FileOutputStream(perUnzipFile);is = zipFile.getInputStream(zipEntry);while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}}}if (fos!=null) {fos.close();}if (is!=null) {is.close();}} catch (Exception e) {e.printStackTrace();}}}
ps:
Java檔案壓縮與解壓縮(一),最好.
Java檔案壓縮與解壓縮(三),其次.