一、首先需要查出来目录和文件的集合,我这边是直接查好的文件和目录,也可以单独查询目录和文件,然后在进行拼装。注意不能将zipOutPutStream.finish()和zipOutPutStream.close()同时使用,会导致压缩包是不可预料的压缩文件末端,这个问题解决了好久,才发现是这个导致的。
如果空文件夹也需要压缩,采用的是以下的方法:
zipOutputStream.putNextEntry(new ZipEntry(emptyFolderList.get(i) + " /"));
/*根据业务id查询的文件和目录集合*/
List<SchemeFileCatalog> list = schemeFileCatalogService.getDetails(busKey);
if (list != null && list.size() > 0) {
String zipName = "方案附件信息.zip";
response.setContentType("application/octet-stream");// 指明response的返回对象是文件流
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(zipName, "UTF-8"));
// ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(new File("D:/a/a.zip")));
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
zipOutputStream.setMethod(ZipOutputStream.DEFLATED);//设置压缩方法
try {
//声明一个存放文件路径的集合
List<File> files = new ArrayList<File>();
//文件夹名
List<String> totalFolderList = new ArrayList<String>();
for (int i = 0;i < list.size(); i++){
//当前目录名
String superFolderName = list.get(i).getFileName();
// 查询该目录下的文件
List<SysFileInfoVo> children = list.get(i).getChildren();
for (int j = 0; j < children.size(); j++) {
//文件名
String fileName = children.get(j).getFileName();
//获取文件在本地的地址
String filePath = FileUtils.appendFilePath(basedir, children.get(j).getPath().substring(8));
//构建二级文件夹名
totalFolderList.add(superFolderName + "\\" + fileName + "\\");
files.add(new File(filePath));
}
}
if (CollectionUtils.isEmpty(files) == false) {
for (int i = 0, size = totalFolderList.size(); i < size; i++) {
//调用工具类方法
ZipUtils.compress(files.get(i), zipOutputStream, totalFolderList.get(i));
}
//强行把Buffer的 内容写到客户端浏览器
response.flushBuffer();
// 冲刷输出流
zipOutputStream.flush();
// zipOutputStream.finish();
// 关闭输出流
zipOutputStream.close();
}
else {
outWriter = response.getWriter();
outWriter.println("<script>alert('该日期暂无文件')';</script>");
return;
}
} catch (Exception e) {
try {
outWriter = response.getWriter();
} catch (IOException e1) {
e1.printStackTrace();
}
logger.error("ImportfileController.java-packdownload-Exception: ", e);
outWriter.println("<script>alert('下载异常')';</script>");
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
二、下边的这个是工具类,如果对上边的代码有疑问可以在工具类中的main方法进行单独的尝试,按照实例来传参就可以了。
package com.mesing.mldp.system.utils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
public class ZipUtils {
private static Logger logger = LoggerFactory.getLogger(ZipUtils.class);
// 目录标识判断符
private static final String PATCH = "/";
// 基目录
private static final String BASE_DIR = "/b/";
// 缓冲区大小
private static final int BUFFER = 2048;
// 字符集
private static final String CHAR_SET = "UTF-8";
public static void compress(File srcFile, ZipOutputStream zipOutputStream, String basePath) throws Exception {
if (srcFile.isDirectory()) {
compressDir(srcFile, zipOutputStream, basePath);
} else {
compressFile(srcFile, zipOutputStream, basePath);
}
}
private static void compressDir(File dir, ZipOutputStream zipOutputStream, String basePath) throws Exception {
try {
// 获取文件列表
File[] files = dir.listFiles();
if (files.length < 1) {
ZipEntry zipEntry = new ZipEntry(basePath + dir.getName() + PATCH);
zipOutputStream.putNextEntry(zipEntry);
zipOutputStream.closeEntry();
}
for (int i = 0,size = files.length; i < size; i++) {
compress(files[i], zipOutputStream, basePath + dir.getName() + PATCH);
}
} catch (Exception e) {
throw new Exception(e.getMessage(), e);
}
}
private static void compressFile(File file, ZipOutputStream zipOutputStream, String dir) throws Exception {
try {
// 压缩文件
ZipEntry zipEntry = new ZipEntry(dir + file.getName());
zipOutputStream.putNextEntry(zipEntry);
// 读取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
int count = 0;
byte data[] = new byte[BUFFER];
while ((count = bis.read(data, 0, BUFFER)) != -1) {
zipOutputStream.write(data, 0, count);
}
bis.close();
zipOutputStream.closeEntry();
} catch (Exception e) {
throw new Exception(e.getMessage(),e);
}
}
public static void main(String[] args) {
try {
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(new File("D:/a/a.zip")));
zipOutputStream.setEncoding(CHAR_SET);
List<File> files = new ArrayList<File>();
files.add(new File("F:\\fileStorage\\template\\upload\\2023\\01\\16\\8d8ec9b8-de59-4476-8bd2-c1b667ca71b0.docx"));
files.add(new File("F:\\fileStorage\\template\\upload\\2023\\01\\16\\38e99679-346d-4832-a8e0-151f7d7886e0.docx"));
if (CollectionUtils.isEmpty(files) == false) {
for (int i = 0,size = files.size(); i < size; i++) {
compress(files.get(i), zipOutputStream, BASE_DIR);
}
}
// 冲刷输出流
zipOutputStream.flush();
// 关闭输出流
zipOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、我使用的 前端是vue,在此方法传参的地方一定要设置上
export function packdownload(query) {
return request({
url: '/scheme/catalog/packdownload',
method: 'get',
params: query,
responseType: 'blob',
})
}
responseType: 'blob',
这个很重要,不然会导致压缩文件损坏。
packdownload({
busKey: ""
}).then(response => {
console.log(response);
let blob = new Blob([response], {type: "application/zip"});
let url = window.URL.createObjectURL(blob);
const link = document.createElement("a"); // 创建a标签
link.href = url;
link.download = "方案附件信息.zip"; // 重命名文件
link.click();
URL.revokeObjectURL(url); // 释放内存
}).catch(function (err) {
console.log(err);
});
四、最后的效果就是