您的位置:首页 > 编程语言 > Java开发

java tar.gz 格式多文件打包压缩与解压

2017-09-06 10:19 609 查看
问题背景:开发中,我们时常会遇到对文件进行存储或传输的问题,但如果传输储存的文件较大,浪费磁盘空间不说,还会大大影响程序运行效率。于是便引出了这篇文章的主题,关于文件打包与压缩的问题。这里“打包”是指,将多个文件合成一个文件;“压缩”是指,把文件的二进制代码压缩,把相邻的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

代码:

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压缩技术(六) BZIP2——Commons实现

Java实现将多个文件打包压缩成tar.gz文件

以上两个连接均为本人学习压缩与解压时曾参考过的文章,非本人所写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: