java 压缩/解压【tar.gz】

时间:2022-09-17 16:36:52

环境

操作系统:win7
java:jdk7
第三方包:commons-compress-1.14.jar

需求

不管是文件夹还是常规文件,实现基本的打包压缩。

思路:
①先把需要压缩的文件,打包成.tar文件。
②使用gzip把刚刚打包的.tar文件进行压缩(tar.gz)

java 压缩/解压【tar.gz】


打包代码

http://commons.apache.org/proper/commons-compress/examples.html

官网:

TarArchiveEntry entry = new TarArchiveEntry(name);
entry.setSize(size);
tarOutput.putArchiveEntry(entry);
tarOutput.write(contentOfEntry);
tarOutput.closeArchiveEntry();

官网给的代码很简单,也就是一个思路。

我的完整代码:

/**
* 归档
* @param entry
* @throws IOException
* @author yutao
* @return
* @date 2017年5月27日下午1:48:23
*/

private static String archive(String entry) throws IOException {
File file = new File(entry);

TarArchiveOutputStream tos = new TarArchiveOutputStream(new FileOutputStream(file.getAbsolutePath() + ".tar"));
String base = file.getName();
if(file.isDirectory()){
archiveDir(file, tos, base);
}else{
archiveHandle(tos, file, base);
}

tos.close();
return file.getAbsolutePath() + ".tar";
}

/**
* 递归处理,准备好路径
* @param file
* @param tos
* @param base
* @throws IOException
* @author yutao
* @date 2017年5月27日下午1:48:40
*/

private static void archiveDir(File file, TarArchiveOutputStream tos, String basePath) throws IOException {
File[] listFiles = file.listFiles();
for(File fi : listFiles){
if(fi.isDirectory()){
archiveDir(fi, tos, basePath + File.separator + fi.getName());
}else{
archiveHandle(tos, fi, basePath);
}
}
}

/**
* 具体归档处理(文件)
* @param tos
* @param fi
* @param base
* @throws IOException
* @author yutao
* @date 2017年5月27日下午1:48:56
*/

private static void archiveHandle(TarArchiveOutputStream tos, File fi, String basePath) throws IOException {
TarArchiveEntry tEntry = new TarArchiveEntry(basePath + File.separator + fi.getName());
tEntry.setSize(fi.length());

tos.putArchiveEntry(tEntry);

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fi));

byte[] buffer = new byte[1024];
int read = -1;
while((read = bis.read(buffer)) != -1){
tos.write(buffer, 0 , read);
}
bis.close();
tos.closeArchiveEntry();//这里必须写,否则会失败
}

上面代码使用方法:只需要调archive(文件或目录路径)

archive方法里面主要调了两个方法archiveDirarchiveHandle,返回的是最后打包文件名的全路径。
archiveDir方法是个递归的方法。目的就是为了把文件夹中里的所有文件都遍历出来。其实更确切的说是把文件相对路径(相对于打包目录,我这里就是test目录)通过递归拼接好,为真正的打包写入操作做准备。
archiveHandle方法,是真正的打包方法。参数为:1、打包输出流2、需要打包的文件3、打包文件里的路径(之前拼接好的路径)。
tos.closeArchiveEntry()这里一定要注意;官网api解释为:
http://commons.apache.org/proper/commons-compress/javadocs/api-release/index.html

所有包含数据的entry都必须调用此方法。
原因是为了满足缓存区基于记录的写入,我们必须缓冲写入流里的数据。因此可能有数据片段仍然被组装(我认为应该是肯能还有数据在缓存区里),所以必须在该条目(entry)关闭之前写入输出流,并写入下个条目。

压缩

这里使用的是gzip进行压缩,该压缩最适合单一文件的压缩,这也是为什么要先打包成tar文件的原因。

我的压缩代码:

/**
* 把tar包压缩成gz
* @param path
* @throws IOException
* @author yutao
* @return
* @date 2017年5月27日下午2:08:37
*/

public static String compressArchive(String path) throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));

GzipCompressorOutputStream gcos = new GzipCompressorOutputStream(new BufferedOutputStream(new FileOutputStream(path + ".gz")));

byte[] buffer = new byte[1024];
int read = -1;
while((read = bis.read(buffer)) != -1){
gcos.write(buffer, 0, read);
}
gcos.close();
bis.close();
return path + ".gz";
}

该方法很简单,没什么好说的。

使用方法:调用compressArchive(需要解压文件的路径)

解压

①先解压tar.gztar
②再对tar进行解压,并删除tar文件。

解压gz文件

官网代码:
http://commons.apache.org/proper/commons-compress/examples.html

InputStream fin = Files.newInputStream(Paths.get("archive.tar.gz"));
BufferedInputStream in = new BufferedInputStream(fin);
OutputStream out = Files.newOutputStream(Paths.get("archive.tar"));
GZipCompressorInputStream gzIn = new GZipCompressorInputStream(in);
final byte[] buffer = new byte[buffersize];
int n = 0;
while (-1 != (n = gzIn.read(buffer))) {
out.write(buffer, 0, n);
}
out.close();
gzIn.close();

我的代码:

/**
* 解压
* @param archive
* @author yutao
* @throws IOException
* @date 2017年5月27日下午4:03:29
*/

private static void unCompressArchiveGz(String archive) throws IOException {

File file = new File(archive);

BufferedInputStream bis =
new BufferedInputStream(new FileInputStream(file));

String fileName =
file.getName().substring(0, file.getName().lastIndexOf("."));

String finalName = file.getParent() + File.separator + fileName;

BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(finalName));

GzipCompressorInputStream gcis =
new GzipCompressorInputStream(bis);

byte[] buffer = new byte[1024];
int read = -1;
while((read = gcis.read(buffer)) != -1){
bos.write(buffer, 0, read);
}
gcis.close();
bos.close();

unCompressTar(finalName);
}

解压tar

官网代码:
http://commons.apache.org/proper/commons-compress/examples.html

TarArchiveEntry entry = tarInput.getNextTarEntry();
byte[] content = new byte[entry.getSize()];
LOOP UNTIL entry.getSize() HAS BEEN READ {
tarInput.read(content, offset, content.length - offset);
}

我的代码:

/**
* 解压tar
* @param finalName
* @author yutao
* @throws IOException
* @date 2017年5月27日下午4:34:41
*/

private static void unCompressTar(String finalName) throws IOException {

File file = new File(finalName);
String parentPath = file.getParent();
TarArchiveInputStream tais =
new TarArchiveInputStream(new FileInputStream(file));

TarArchiveEntry tarArchiveEntry = null;

while((tarArchiveEntry = tais.getNextTarEntry()) != null){
String name = tarArchiveEntry.getName();
File tarFile = new File(parentPath, name);
if(!tarFile.getParentFile().exists()){
tarFile.getParentFile().mkdirs();
}

BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(tarFile));

int read = -1;
byte[] buffer = new byte[1024];
while((read = tais.read(buffer)) != -1){
bos.write(buffer, 0, read);
}
bos.close();
}
tais.close();
file.delete();//删除tar文件
}

如何使用上面的代码

public static void main(String[] args) throws IOException {

String entry = "C:\\Users\\yutao\\Desktop\\pageage\\test";//需要压缩的文件夹
String archive = archive(entry);//生成tar包
String path = compressArchive(archive);//生成gz包

// unCompressArchiveGz("C:\\Users\\yutao\\Desktop\\pageage\\test.tar.gz");//解压
}

参考地址:
http://snowolf.iteye.com/blog/648652