天天看點

Java Zip壓縮實作

最近在自學javaWeb,先複習一下java,把還給老師的東西再找回來(知識如果不用很快就會忘記啊)。。

今天看到了zip壓縮,決定要整理一下。

java将有關zip壓縮的内容都封裝在java.util.zip寶中,用java實作zip壓縮,不用考慮壓縮算法,java已經将這些進行了封裝

實際上用java實作zip壓縮涉及的就是一個“輸入輸出流”的概念

用java實作一個檔案的zip壓縮,過程可以簡單地表示為:

Java Zip壓縮實作

當然具體實作要比這個複雜一點,比如要先像zip檔案中寫入目錄進入點。。如果要壓縮檔案夾中的内容要周遊檔案夾中的檔案和子檔案夾。

先給出源代碼,再解釋:

import java.io.*;
import java.util.*;
import java.util.zip.*;

class ZipCompress
{
    private String zipFileName;      // 目的地Zip檔案
    private String sourceFileName;   //源檔案(帶壓縮的檔案或檔案夾)
    
    public ZipCompress(String zipFileName,String sourceFileName)
    {
        this.zipFileName=zipFileName;
        this.sourceFileName=sourceFileName;
    }
    
    public void zip() throws Exception
    {
        //File zipFile = new File(zipFileName);
        System.out.println("壓縮中...");
        
        //建立zip輸出流
        ZipOutputStream out = new ZipOutputStream( new FileOutputStream(zipFileName));
        
        //建立緩沖輸出流
        BufferedOutputStream bos = new BufferedOutputStream(out);
        
        File sourceFile = new File(sourceFileName);
        
        //調用函數
        compress(out,bos,sourceFile,sourceFile.getName());
        
        bos.close();
        out.close();
        System.out.println("壓縮完成");
        
    }
    
    public void compress(ZipOutputStream out,BufferedOutputStream bos,File sourceFile,String base) throws Exception
    {
        //如果路徑為目錄(檔案夾)
        if(sourceFile.isDirectory())
        {
        
            //取出檔案夾中的檔案(或子檔案夾)
            File[] flist = sourceFile.listFiles();
            
            if(flist.length==0)//如果檔案夾為空,則隻需在目的地zip檔案中寫入一個目錄進入點
            {
                System.out.println(base+"/");
                out.putNextEntry(  new ZipEntry(base+"/") );
            }
            else//如果檔案夾不為空,則遞歸調用compress,檔案夾中的每一個檔案(或檔案夾)進行壓縮
            {
                for(int i=0;i<flist.length;i++)
                {
                    compress(out,bos,flist[i],base+"/"+flist[i].getName());
                }
            }
        }
        else//如果不是目錄(檔案夾),即為檔案,則先寫入目錄進入點,之後将檔案寫入zip檔案中
        {
            out.putNextEntry( new ZipEntry(base) );
            FileInputStream fos = new FileInputStream(sourceFile);
            BufferedInputStream bis = new BufferedInputStream(fos);
            
            int tag;
            System.out.println(base);
            //将源檔案寫入到zip檔案中
            while((tag=bis.read())!=-1)
            {
                bos.write(tag);
            }
            bis.close();
            fos.close();
            
        }
    }
}
public class TestZip 
{

    public static void main(String[] args)
    {
        ZipCompress zipCom = new ZipCompress("D:\\電影.zip","F:\\電影");
        try
        {
            zipCom.zip();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}      

zip()方法中首先建立了ZipOutputStream(zip輸出流)之後調用compress()方法

在compress()方法中通過遞歸完成将檔案夾中的每個檔案的壓縮。

具體為:

首先判斷輸入的檔案是檔案夾還是檔案,如果是檔案,直接壓縮,如果是檔案夾則要遞歸調用compress()周遊壓縮檔案夾中的檔案。

如果是檔案,首先在zip檔案中寫入一個目錄進入點(所謂目錄進入點,個人了解就是源檔案在目标zip檔案中的路徑)

然後用檔案輸入流FileInputStream将源檔案讀入記憶體,在用ZipOutputStream(zip輸出流)将讀入記憶體的資料寫入到zip檔案中,這就完成了壓縮。(實際上就是輸入輸出流)

當檔案夾為空的時候,隻需寫入一個目錄進入點(要注意最後一定要加一個"\",表示一個目錄)。

運作結果為:

源檔案:

Java Zip壓縮實作

其中檔案夾1中含有兩個檔案,檔案夾2 為空。

壓縮後的檔案為:

Java Zip壓縮實作

前面提到的空檔案夾的目錄進入點一定要加"\",以表示一個檔案夾,而不是一個檔案,我們可以把程式中的"\"去掉,這時結果為:

Java Zip壓縮實作

可以看到本來是檔案夾的檔案夾2,程式設計了檔案。是以可以把目錄進入點就了解為,源檔案在zip檔案中對應的路徑,這個相對路徑應該與源檔案夾中的相對路徑一緻,當然也可以不一緻,比如我們在base前加入一個字元串"我愛",

out.putNextEntry( new ZipEntry("我愛"+base) );

結果為:

Java Zip壓縮實作

可以看到zip中的根目錄變成了“我愛電影”而不是原來的電影

Java Zip壓縮實作

 水準有限。。。請多多指教。。。。