欢迎大家关注本博,同时欢迎大家评论交流,可以给个赞哦!!!
Zip是常用的无损压缩算法实现,Java中提供了Zip的实现,本文演示基于磁盘的方式进行压缩和解压,演示只针对一层目录结构进行,多层目录只需递归操作进行即可。
文中提供完整的工具类,以供大家使用。
Maven依赖
ant: ant: 1.8.0:JDK1.7以下版本环境下,JDK原生的ZIP流处理会出现中文条目乱码的问题,此依赖提供了ZIP相关的流实现, 可以完美的解决低版本JDK出现的问题。JDK1.7及JDK1.7+版本上已无此问题。
commons-io: commons-io: 2.4: JDK原生的流操作是比较繁琐的,例如:流的开闭处理、流的转换处理等,会使得代码无序且凌乱。commons-io针对IO操作提供了良好的封装,可以使用简单的操作完成繁杂的处理,commons-io本身已经对IO做了相对完善的封装。
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
工具类
其实,在通常情况下,我们都是在磁盘上进行压缩和解压操作的,这样虽然增加了操作的复杂度,但是却无形中避免了一些问题。
下面是提供的ZIP算法实现的工具类,提供了compressByZip、compressByZipJdkLower7、decompressByZip三个方法,在无特殊需求的情况下,基本可以满足压缩和解压的需求,代码如下:
package com.arhorchin.securitit.compress.zip;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
/**
* @author Securitit.
* @note 基于磁盘以ZIP算法进行压缩和解压工具类.
*/
public class ZipDiskUtil {
/**
* logger.
*/
private static Logger logger = Logger.getLogger(ZipDiskUtil.class);
/**
* 条目名称使用的默认字符.
*/
public final static String CHARSET_GBK = "GBK";
/**
* 使用ZIP算法进行压缩.
* @param sourceFolderPath 待进行压缩的文件夹路径.
* @param targetZipFilePath 压缩后的ZIP文件存储目录.
* @return 压缩是否成功.
* @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
*/
public static boolean compressByZip(String sourceFolderPath, String targetZipFilePath) throws Exception {
// 变量定义.
File sourceFolderFile = null;
ZipOutputStream zipZos = null;
FileOutputStream zipFos = null;
InputStream singleFileIs = null;
File[] sourceFilesInFolder = null;
try {
// 取得待压缩文件列表.
sourceFolderFile = new File(sourceFolderPath);
sourceFilesInFolder = sourceFolderFile.listFiles();
// 压缩文件变量初始化.
zipFos = new FileOutputStream(new File(targetZipFilePath));
zipZos = new ZipOutputStream(zipFos);
// 将文件添加到ZIP条目中.
for (File singleFile : sourceFilesInFolder) {
zipZos.putNextEntry(new ZipEntry(singleFile.getName()));
singleFileIs = new FileInputStream(singleFile);
IOUtils.copy(singleFileIs, zipZos);
}
} catch (Exception ex) {
logger.info("ZipDiskUtil.compressByZip.", ex);
return false;
} finally {
if (null != singleFileIs)
singleFileIs.close();
if (null != zipZos)
zipZos.close();
if (null != zipFos)
zipFos.close();
}
return true;
}
/**
* 使用ZIP算法进行压缩.JDK1.7版本一下,对中文处理不是很友好,可以使用这个方法解决.
* @param sourceFolderPath 待进行压缩的文件夹路径.
* @param targetZipFilePath 压缩后的ZIP文件存储目录.
* @return 压缩是否成功.
* @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
*/
public static boolean compressByZipJdkLower7(String sourceFolderPath, String targetZipFilePath) throws Exception {
return compressByZipJdkLower7(sourceFolderPath, targetZipFilePath, CHARSET_GBK);
}
/**
* 使用ZIP算法进行压缩.JDK1.7版本一下,对中文处理不是很友好,可以使用这个方法解决.
* @param sourceFolderPath 待进行压缩的文件夹路径.
* @param targetZipFilePath 压缩后的ZIP文件存储目录.
* @param charset 压缩条目使用的字符集.
* @return 压缩是否成功.
* @throws Exception 压缩过程中可能发生的异常,若发生异常,则不会生成ZIP文件.
*/
public static boolean compressByZipJdkLower7(String sourceFolderPath, String targetZipFilePath, String charset)
throws Exception {
// 变量定义.
File sourceFolderFile = null;
FileOutputStream zipFos = null;
InputStream singleFileIs = null;
File[] sourceFilesInFolder = null;
org.apache.tools.zip.ZipOutputStream zipZos = null;
try {
// 取得待压缩文件列表.
sourceFolderFile = new File(sourceFolderPath);
sourceFilesInFolder = sourceFolderFile.listFiles();
// 压缩文件变量初始化.
zipFos = new FileOutputStream(new File(targetZipFilePath));
zipZos = new org.apache.tools.zip.ZipOutputStream(zipFos);
// 设置条目名称编码.
zipZos.setEncoding(charset);
// 将文件添加到ZIP条目中.
for (File singleFile : sourceFilesInFolder) {
zipZos.putNextEntry(new org.apache.tools.zip.ZipEntry((singleFile.getName())));
singleFileIs = new FileInputStream(singleFile);
IOUtils.copy(singleFileIs, zipZos);
}
} catch (Exception ex) {
logger.info("ZipDiskUtil.compressByZipJdkLower7.", ex);
return false;
} finally {
if (null != singleFileIs)
singleFileIs.close();
if (null != zipFos)
zipFos.close();
if (null != zipZos)
zipZos.close();
}
return true;
}
/**
* 使用ZIP算法进行解压.
* @param sourceZipPath 待解压文件路径.
* @param targetFolderPath 解压后文件夹目录.
* @return 解压是否成功.
* @throws Exception 解压过程中可能发生的异常,若发生异常,则不会生成文件夹.
*/
public static boolean decompressByZip(String sourceZipPath, String targetFolderPath) throws Exception {
// 变量定义.
ZipEntry singleZipEntry;
String zipEntryName = null;
ZipInputStream zipZis = null;
FileInputStream zipFis = null;
BufferedInputStream zipBis = null;
try {
// 解压变量初始化.
zipFis = new FileInputStream(new File(sourceZipPath));
zipBis = new BufferedInputStream(zipFis);
zipZis = new ZipInputStream(zipBis);
// 条目解压缩至指定文件夹目录下.
while ((singleZipEntry = zipZis.getNextEntry()) != null) {
zipEntryName = singleZipEntry.getName();
FileUtils.writeByteArrayToFile(new File(targetFolderPath + File.separator + zipEntryName),
IOUtils.toByteArray(zipZis));
}
} catch (Exception ex) {
logger.info("ZipDiskUtil.decompressByZip.", ex);
return false;
} finally {
if (null != zipFis)
zipFis.close();
if (null != zipZis)
zipZis.close();
if (null != zipBis)
zipBis.close();
}
return true;
}
}
工具类测试
在Maven依赖引入正确的情况下,复制上面的代码到项目中,修改package,可以直接使用,下面我们对工具类进行简单测试。测试类代码如下:
package com.arhorchin.securitit.compress.zip;
import com.arhorchin.securitit.compress.zip.ZipDiskUtil;
/**
* @author Securitit.
* @note ZipDiskUtil工具类测试.
*/
public class ZipDiskUtilTester {
public static void main(String[] args) throws Exception {
ZipDiskUtil.compressByZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/files", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip");
ZipDiskUtil.decompressByZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.zip", "C:/Users/Administrator/Downloads/个人文件/2020-07-13-01/disk");
}
}
运行测试后,通过查看disk.zip和解压的目录,可以确认工具类运行结果无误。
总结
1) 在小文件、文件数量较小且较为固定时,提倡使用基于内存压缩和解压方式。使用内存换时间,减少频繁的磁盘操作。可以参见《Java Zip 基于内存实现压缩和解压》
2) 在大文件、文件数量较大时,提倡使用基于磁盘压缩和解压方式。过大文件对服务会造成过度的负载,磁盘压缩和解压可以缓解这种压力。
3) JDK1.6及以下版本中,JDK提供的java.util.zip.*进行压缩时,对于中文条目名称处理会出现乱码,需要额外引用Ant包,使用其org.apache.tools.zip.*来解决这个问题。
本博微信公众号“超哥说码”,欢迎大家订阅,公众号正在完善中,会及时将更优质的博文推送于您!