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格式文件之归档、打包、压缩、解压缩》

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