java tar.gz 格式多文件打包壓縮與解壓

問題背景:開發中,我們時常會遇到對文件進行存儲或傳輸的問題,但如果傳輸儲存的文件較大,浪費磁盤空間不說,還會大大影響程序運行效率。於是便引出了這篇文章的主題,關於文件打包與壓縮的問題。這裏“打包”是指,將多個文件合成一個文件;“壓縮”是指,把文件的二進制代碼壓縮,把相鄰的0,1代碼減少,比如有000000,可以把它變成6個0 的寫法60,來減少該文件的空間。
舉例:在PC端中,有很多壓縮軟件,如:WinRAR、2345好壓等。他們通常是將文件打包與壓縮和爲一體執行的。簡單來說,當我們要壓縮的文件夾裏包含多個文件時,壓縮軟件會先將文件夾打包成一個文件後再進行二進制代碼壓縮。就像Linux中 tar 與 gzip 命令一樣,一個負責打包,一個負責壓縮。
壓縮率: bz2 > gz > zip。看到這裏,可能有人會問,爲什麼沒有.rar格式的文件呢?那是因爲,.rar格式是一種文件壓縮與歸檔的私有專利壓縮格式。其作者,僅有條件的公開了解碼程序的源代碼,但是編碼程序仍然是私有的。(PS:由於zip文件壓縮率太低所以很少被使用,但zip格式文件也是有優點的,最明顯的是,.zip格式的文件可以在Windows和Linux中不安裝任何解壓軟件的情況下解壓。)

說了這麼多,接下來我們就開始動手吧!

(由於有同學反饋該篇文章的功能不夠全面,因此博主進行了功能升級建議查看 下篇文章 進行效仿,以節約您寶貴的時間)

依賴jar包:
commons-compress-1.12.jar
commons-io-2.4.jar

代碼:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.IOUtils;

/**
 * 多文件壓縮與解壓
 * @author Supreme_Sir
 */
 
public class Compress {
    private final static int BUFFER = 1048576;
    
    /**
     * 解壓tar.gz文件
     * @param tar_gz
     * @param sourceFolder
     */
    public void decompress(File tar_gz,String sourceFolder){
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        GZIPInputStream gzis = null;
        TarArchiveInputStream tais = null;
        OutputStream out = null;
        try {
            fis = new FileInputStream(tar_gz);
            bis = new BufferedInputStream(fis);
            gzis = new GZIPInputStream(bis);
            tais = new TarArchiveInputStream(gzis);
            TarArchiveEntry tae = null;
            boolean flag = false;
            while((tae = tais.getNextTarEntry()) != null ){
                File tmpFile = new File(sourceFolder+tae.getName());
                if(! flag){
                    //使用 mkdirs 可避免因文件路徑過多而導致的文件找不到的異常
                    new File(tmpFile.getParent()).mkdirs();
                    flag = true;
                }
               out = new FileOutputStream(tmpFile);
                int length = 0; 
                byte[] b = new byte[BUFFER];
                while((length = tais.read(b)) != -1){
                    out.write(b, 0, length); 
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(tais != null)  tais.close();
                if(gzis != null) gzis.close();
                if(bis != null) bis.close();
                if(fis != null) fis.close();
                if(out != null){
                    out.flush();
                    out.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  /**
   * 壓縮tar文件
   * @param list
   * @param outPutPath
   * @param fileName
   */
    public File compresser(ArrayList<File> list,String outPutPath,String fileName){
        File outPutFile = null;
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        GZIPOutputStream gzp = null;
        File tar = new File("C:/temp.tar");
        try {
            fis = new FileInputStream(pack(list,tar));
            bis = new BufferedInputStream(fis,BUFFER);
            outPutFile = new File(outPutPath+"/"+fileName+".tar.gz");
            fos = new FileOutputStream(outPutFile);
            gzp = new GZIPOutputStream(fos);
            int count;  
            byte data[] = new byte[BUFFER];  
            while ((count = bis.read(data, 0, BUFFER)) != -1) {  
                gzp.write(data, 0, count);  
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(gzp != null){
                    gzp.finish();
                    gzp.flush();
                    gzp.close();
                }
                if(fos != null)  fos.close();
                if(bis != null)  bis.close();
                if(fis != null)  fis.close();
                if(tar.exists()){
                    tar.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return outPutFile;
    }
    
    
    /**
     * 私有函數將文件集合壓縮成tar包後返回
     * @param files   要壓縮的文件集合
     * @param target  tar.輸出流的目標文件
     * @return File  指定返回的目標文件
     */
    private File pack(ArrayList<File> files, File target){
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        TarArchiveOutputStream taos = null;
        FileInputStream fis = null;
        try {
            fos  = new FileOutputStream(target);
            bos = new BufferedOutputStream(fos,BUFFER);
            taos = new TarArchiveOutputStream(bos);
            //解決文件名過長問題
            taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
            for(File file : files){
                taos.putArchiveEntry(new TarArchiveEntry(file));
                fis = new FileInputStream(file);
                IOUtils.copy(fis, taos);
                taos.closeArchiveEntry();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(fis != null) fis.close();
                if(taos != null){
                    taos.finish();
                    taos.flush();
                    taos.close();
                }
                if(bos != null){
                    bos.flush();
                    bos.close();
                }
                if(fos != null){
                    fos.flush();
                    fos.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return target;
    }
}

結語: 最後,細心的人可能會問,上文中說 .bz2 格式的文件爲壓縮率最高的文件,可爲什麼沒有選擇 .bz2 格式進行文件壓縮。這裏我想說明的是,可能是因爲兩種壓縮算法不同的原因, 當我對一個139M的文件夾進行打包壓縮時,使用.bz2算法壓縮需要35秒的時間,而當我使用.gz格式的文件只需要15秒的時間,且文件大小僅差3M。因此,綜合考慮後,我選擇了.gz格式的壓縮文件。

下一篇:《Java生成tar.gz格式文件之歸檔、打包、壓縮、解壓縮》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章