打包压缩成zip到磁盘目录或zip作为http响应
压缩工具类1
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
public class ZipUtils {
private static final int BUFFER_SIZE = 2 * 1024;
/**
* 目录压缩成ZIP 方法1
*
* @param srcDir 压缩文件夹路径
* @param out 压缩文件输出流,浏览器响应则用response.getOutputStream()
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* <p>
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
throws RuntimeException {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
File sourceFile = new File(srcDir);
compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
long end = System.currentTimeMillis();
log.info("压缩完成,耗时:{}ms", end - start);
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 多个文件打成一个压缩包
*
* @param srcFiles 需要压缩的文件列表
* @param out 压缩文件输出流
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(List<File> srcFiles, OutputStream out) throws RuntimeException {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
for (File srcFile : srcFiles) {
byte[] buf = new byte[BUFFER_SIZE];
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
}
long end = System.currentTimeMillis();
log.info("压缩完成,耗时:{}ms", end - start);
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 递归压缩
*
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* <p>
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws Exception
*/
private static void compress(File sourceFile, ZipOutputStream zos, String name,
boolean KeepDirStructure) throws Exception {
byte[] buf = new byte[BUFFER_SIZE];
if (sourceFile.isFile()) {
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
zos.putNextEntry(new ZipEntry(name));
// copy文件到zip输出流中
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
// Complete the entry
zos.closeEntry();
in.close();
} else {
File[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
// 需要保留原来的文件结构时,需要对空文件夹进行处理
if (KeepDirStructure) {
// 空文件夹的处理
zos.putNextEntry(new ZipEntry(name + "/"));
// 没有文件,不需要文件的copy
zos.closeEntry();
}
} else {
for (File file : listFiles) {
// 判断是否需要保留原来的文件结构
if (KeepDirStructure) {
// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
} else {
compress(file, zos, file.getName(), KeepDirStructure);
}
}
}
}
}
//测试方法
public static void main(String[] args) throws Exception {
//测试压缩方法1 将磁盘目录打包,并将压缩包写到磁盘
FileOutputStream fos = new FileOutputStream(new File("D:\\test\\1613722789624.zip"));
ZipUtils.toZip("D:\\test\\1613722789624", fos, true);
/** 测试压缩方法2 */
/*
List<File> fileList = new ArrayList<>();
fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/jar.exe"));
fileList.add(new File("D:/Java/jdk1.7.0_45_64bit/bin/java.exe"));
FileOutputStream fos2 = new FileOutputStream(new File("c:/mytest02.zip"));
ZipUtils.toZip(fileList, fos2);*/
}
}
压缩工具类2
使用zip4j,封装好的api,功能易用,参考https://www.jianshu.com/p/89bf65317e6b
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
工具类
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
public class ZipFiles {
/**
* 压缩目录到磁盘zip
* @throws ZipException
*/
public static void zipFile() throws ZipException {
// 生成的压缩文件
ZipFile zipFile = new ZipFile("C:\\Users\\yckj2494\\Desktop\\a.zip");
ZipParameters parameters = new ZipParameters();
// 压缩方式
parameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
// 压缩级别
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_FASTEST);
// 要打包的文件夹
File currentFile = new File("C:\\Users\\yckj2494\\Desktop\\20210224160154710");
File[] fs = currentFile.listFiles();
// 遍历test文件夹下所有的文件、文件夹
for (File f : fs) {
if (f.isDirectory()) {
zipFile.addFolder(f.getPath(), parameters);
} else {
zipFile.addFile(f, parameters);
}
}
}
/**
* http响应zip
* @param srcDir
* @param out
* @throws ZipException
* @throws IOException
*/
public static void zipFile(String srcDir, OutputStream out ) throws ZipException, IOException {
final long start = System.currentTimeMillis();
// 要打包的文件夹
File currentFile = new File(srcDir);
// 生成的压缩文件
final File file = new File(srcDir + ".zip");
ZipFile zipFile = new ZipFile(file);
ZipParameters parameters = new ZipParameters();
// 压缩方式
parameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
// 压缩级别
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_FASTEST);
File[] fs = currentFile.listFiles();
// 遍历test文件夹下所有的文件、文件夹
for (File f : fs) {
if (f.isDirectory()) {
zipFile.addFolder(f.getPath(), parameters);
} else {
zipFile.addFile(f, parameters);
}
}
try( InputStream fis = new FileInputStream(zipFile.getFile())) {
IOUtils.copy(fis, out);
}
file.delete();
log.info("打包耗时={}ms",System.currentTimeMillis()-start);
}
/**
* 解压zip
* @param zipFile
* @throws ZipException
*/
public static void unzip(String zipFile) throws ZipException {
long startTime = System.currentTimeMillis();
ZipFile zipFile2 = new ZipFile(zipFile);
//设置编码格式
zipFile2.setFileNameCharset("gbk");
if (!zipFile2.isValidZipFile()) {
//可能不是zip文件,可能是rar
throw new ZipException("文件不合法或不存在");
}
//检查是否需要密码
//checkEncrypted(zipFile2);
List<FileHeader> fileHeaderList = zipFile2.getFileHeaders();
for (int i = 0; i < fileHeaderList.size(); i++) {
FileHeader fileHeader = fileHeaderList.get(i);
zipFile2.extractFile(fileHeader, "temp");
}
System.out.println("解压成功!");
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime) + "ms");
}
public static void main(String[] args) throws ZipException {
final long start = System.currentTimeMillis();
zipFile();
final long time = System.currentTimeMillis() - start;
System.out.println("耗时="+time);
}
}
更简单的解压zip方式:
final ZipFile zipFile = new ZipFile("temp\\b.zip");
zipFile.extractAll("temp\\b");
HTTP响应zip压缩包
@GetMapping("/getZip")
public Object getModelExcel(HttpServletResponse response) {
//设置response的header
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=test.zip");
//方式1,使用java原生方式
//调用工具类,将test文件夹压缩成zip包并写入到http响应流,保留目录结构,
ZipUtils.toZip("D:\\test", response.getOutputStream(), true);
//方式2,使用zip4j,不压缩打包,速度更快
ZipFiles.zipFile("D:\\test", response.getOutputStream());
return null;
}
解压rar
引入依赖junrar
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>7.4.0</version>
</dependency>
使用:
直接用junrar提供的静态方法即可
Junrar.extract(压缩文件的路径, 解压到的文件夹);
还提供了多个重载的解压方法: