2010年做项目的时候偶尔要用到压缩解压目录相关操作,本来以为随便网上搜索一下就有,结果找了半天都没找到,无奈去看下apacheCompress的api,自己写了个。,使用了apache的Compress,common-io。
有一个比较容易出错的地方,有些压缩方法,如果压缩目录中有空文件夹,可能是解压不出来的,
这是因为压缩的时候,只对于文件写了entryName,文件夹的entryName没有写。
这种情况下,zip文件的entry树结构:大概如下:
+目录A/目录B/目录C/文件1
+目录A/目录B/目录D/文件2
这种解压的时候如果CD层没有另外的目录,结果与正常的压缩方法没区别,层级目录能正常创建。
但是如果有一个E的空目录和在CD同级的情况,解压完不会有E目录
正常的压缩目录应该为
+目录A
+目录A/目录B
+目录A/目录B/目录C
+目录A/目录B/目录D
+目录A/目录B/目录E
+目录A/目录B/目录C/文件1
+目录A/目录B/目录D/文件2
附代码:
public final class ZipTools {
private int bufferLen = 1024 * 1024;
/**
* 私有化构造方法,prevents calls from subclass
*/
private ZipTools() {
throw new UnsupportedOperationException();
}
private ZipTools(int bufferLen) {
this.bufferLen = bufferLen;
}
public static ZipTools getInstance() {
return new ZipTools(1024 * 1024);
}
public static ZipTools getInstance(int bufferLen) {
return new ZipTools(bufferLen);
}
/**
* 用于单文件压缩
*/
protected void doCompress(File srcFile, File destFile) throws IOException {
ZipArchiveOutputStream out = null;
InputStream is = null;
try {
is = new BufferedInputStream(new FileInputStream(srcFile), bufferLen);
out = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(destFile), bufferLen));
ZipArchiveEntry entry = new ZipArchiveEntry(srcFile.getName());
entry.setSize(srcFile.length());
out.putArchiveEntry(entry);
IOUtils.copy(is, out);
out.closeArchiveEntry();
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(out);
}
}
/**
* 解压文件
* @param zipFile
* @param outDir
* @throws IOException
* 90s
*/
public void doDecompress(String zipFilePath, String outDirStr) throws IOException {
File zipFile = new File(zipFilePath);
File outDir = new File(outDirStr);
ZipArchiveInputStream is = null;
try {
is = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile), bufferLen));
ZipArchiveEntry entry = null;
while ((entry = is.getNextZipEntry()) != null) {
if (entry.isDirectory()) {
File directory = new File(outDir, entry.getName());
directory.mkdirs();
} else {
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(new File(outDir, entry.getName())),
bufferLen);
IOUtils.copy(is, os);
} finally {
IOUtils.closeQuietly(os);
}
}
}
} finally {
IOUtils.closeQuietly(is);
}
}
/**
* 解压指定zip文件到目录,使用新方法
* @param outDir 输出到的目录,此目录如果不存在会自动创建
* @param unZipfileName 需要解压的zip文件名
* @throws IOException
* 30s
*/
public static void unZip(String outDirPath, String unZipfilePath) throws IOException {
FileOutputStream fileOutStream = null;
InputStream inputStream = null;
ZipFile zipFile = null;
File outDir = new File(outDirPath);
File unZipfile = new File(unZipfilePath);
if (!unZipfile.exists()) {
throw new FileNotFoundException("File to upzip:" + unZipfilePath + " not found!");
}
try {
zipFile = new ZipFile(unZipfile);
Enumeration<?> e = zipFile.getEntries();
while (e.hasMoreElements()) {
ZipArchiveEntry entry = (ZipArchiveEntry) e.nextElement();
File file = new File(outDir, entry.getName());
//File file = getRealFileName(outDirPath, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
// 如果指定文件的目录不存在,则创建之.
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
try {
inputStream = zipFile.getInputStream(entry);
fileOutStream = new FileOutputStream(file);
IOUtils.copy(inputStream, fileOutStream);
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(fileOutStream);
}
}
}
} finally {
ZipFile.closeQuietly(zipFile);
IOUtils.closeQuietly(inputStream);
}
}
/**
* 从文件中解压一个指定文件
* @param fileName
* @param zipFile
* @return
* @throws IOException
* @throws ZipException
*/
public InputStream readFileFromSingleFile(ZipFile zipFile, ZipArchiveEntry entry) throws IOException {
InputStream inputStream = zipFile.getInputStream(entry);
return inputStream;
}
/**
* 把一个目录打包到一个指定的zip文件中
* @param dirStr 目录绝对地址
* @param pathName zip文件内相对结构
* @throws IOException
*/
private void packFiles(ZipArchiveOutputStream out, File dir, String pathName) throws IOException {
InputStream is = null;
//返回此绝对路径下的文件
File[] files = dir.listFiles();
if (files == null || files.length < 1) {
return;
}
for (int i = 0; i < files.length; i++) {
File zFile = files[i];
out.putArchiveEntry(new ZipArchiveEntry(zFile, pathName + zFile.getName()));
//判断此文件是否是一个文件夹
if (zFile.isDirectory()) {
packFiles(out, zFile, pathName + zFile.getName() + "/");
} else {
try {
//out.putArchiveEntry(new ZipArchiveEntry(pathName + files[i].getName()));
is = new BufferedInputStream(new FileInputStream(zFile), bufferLen);
IOUtils.copy(is, out);
} finally {
is.close();
}
}
}
}
/**
* 压缩文件或者文件夹
* @param srcFileStr 待压缩文件或文件夹路径
* @param destFileStr 目标文件路径
* @throws IOException
*/
public void zip(String srcFileStr, String destFileStr) throws IOException {
File destFile = new File(destFileStr);
File srcFile = new File(srcFileStr);
zip(srcFile, destFile);
}
/**
* 压缩文件
* @param srcFile 待压缩文件或文件夹
* @param destFile目标压缩文件
* @throws IOException
*/
public void zip(File srcFile, File destFile) throws IOException {
ZipArchiveOutputStream out = null;
// 如果压缩文件存放目录不存在,则创建之.
File pfile = destFile.getParentFile();
if (!pfile.exists()) {
pfile.mkdirs();
}
//如果是文件
if (srcFile.isFile()) {
doCompress(srcFile, destFile);
return;
} else {
try {
out = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(destFile), bufferLen));
packFiles(out, srcFile, "");
out.closeArchiveEntry();
} finally {
IOUtils.closeQuietly(out);
}
}
}
/**
* 将压缩文件中部分文件压缩到另外一个文件中
*/
public void copyEntryToAnother(ZipFile srcFile, File destFile, ArrayList<ZipArchiveEntry> entryList)
throws IOException {
ZipArchiveOutputStream out = null;
FileOutputStream fileOutStream = null;
InputStream inputStream = null;
//建立临时目录
String tempDirStr = System.getProperty("java.io.tmpdir") + "temp"
+ File.separatorChar;
File tempDir = new File(tempDirStr, String.valueOf(FlowNoGenerator.instance().getFlowNo()));
tempDir.mkdirs();
try {
//解压
for (ZipArchiveEntry entry : entryList) {
File file = new File(tempDir, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
// 如果指定文件的目录不存在,则创建之.
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
try {
inputStream = srcFile.getInputStream(entry);
fileOutStream = new FileOutputStream(file);
IOUtils.copy(inputStream, fileOutStream);
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(fileOutStream);
}
}
}
//压缩
zip(tempDir, destFile);
} finally {
FileUtils.deleteQuietly(tempDir);
}
IOUtils.closeQuietly(out);
}
}