1. 程式人生 > >java tar.gz 格式多檔案打包壓縮與解壓

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中不安裝任何解壓軟體的情況下解壓。)

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

程式碼:


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格式的壓縮檔案。

相關連線:

以上兩個連線均為本人學習壓縮與解壓時曾參考過的文章,非本人所寫。