环境
操作系统:win7
java:jdk7
第三方包:commons-compress-1.14.jar
需求
不管是文件夹还是常规文件,实现基本的打包压缩。
思路:
①先把需要压缩的文件,打包成.tar
文件。
②使用gzip
把刚刚打包的.tar
文件进行压缩(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
方法里面主要调了两个方法archiveDir
和archiveHandle
,返回的是最后打包文件名的全路径。
②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.gz
成tar
②再对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");//解压
}