java 壓縮與解壓

最近複習到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

 

-----------------以上-----------------遞歸

相關文章
相關標籤/搜索