@IT·互联网简友广场技术研发汇集

Vue + SpringBoot + zip4j实现文件的压缩下

2025-01-16  本文已影响0人  知信学源

最近在项目当中遇到一个需要解压文件为zip,通过前端进行下载,这和常规的文件下载不同,在 zip 文件还会存在目录,目录中再存放文件,当时找了很多资料都不尽人意,所以自己写了这篇文字供以后参考。SpringBoot 的版本为2.5.15,zip4j 的版本为 2.11.5

Zip4j

zip4j是一个功能强大的 Java 库,专门用于处理 ZIP 文件格式。它提供了一系列易于使用的 API,使得开发人员可以方便地在 Java 应用程序中执行各种 ZIP 文件操作,包括创建、读取、更新和提取 ZIP 文件等。GitHub地址 里面说明了各种 API 的使用和示例。

思路

具体思路是打算通过 zip4j 创建一个 zip 文件,然后通过 API 在 zip 文件里面创建目录和文件。当时的业务需求是下载每一个文件的附录文件,每一个文件都会有多个附录文件,不可能去一个个下载,所以需压缩为 zip 格式。具体的代码如下:

/**

// 创建一个列表用于存放所有附件文件的路径,后续统一压缩到一个zip文件中
List<String> allFilePaths = new ArrayList<>();

// 循环查询每个id对应的附件文件路径并添加到列表中
// 里面的代码大家可能会觉得麻烦,不用细看,只需要知道这层for循环是为了找到附录文件在磁盘的地址
for (int id : intArray) {
List<SysDownloadCenterAttachment> attachmentList = sysDownloadCenterAttachmentMapper.selectList(new LambdaQueryWrapper<SysDownloadCenterAttachment>()
.eq(SysDownloadCenterAttachment::getDownloadCenterId, id));
if (!CollectionUtils.isEmpty(attachmentList)) {
List<String> filePaths = attachmentList.stream().map(attachment -> {
String filePath = scjtConfig.getUploadPath() + attachment.getLocation();
if (!StringUtils.startsWith(filePath, "D:")) {
filePath = "D:" + filePath;
}
return filePath;
}).collect(Collectors.toList());
allFilePaths.addAll(filePaths);
}
}

// 创建ZipFile对象,指定zip文件的路径
ZipFile zipFile = new ZipFile("d:/filename.zip");

// 循环附录文件地址
for (String filePath : allFilePaths) {
File file = new File(filePath);
if (file.exists()) {
// 获取文件名(包含后缀)
String fileName = file.getName();
// 这里假设附件所属的id可以通过某种方式获取,比如从文件路径解析或者其他逻辑判断,示例中用一个方法 getFileIdFromPath 来表示获取id的逻辑,你需要根据实际情况替换
String folderNameInsideZip = getFileTitleFromPath(intArray, filePath);
// 构造在zip文件中存放的路径,格式为 "id标识的文件夹名/原文件名"
try {

// 尝试获取目标文件夹在zip文件中的FileHeader
FileHeader folderHeader = zipFile.getFileHeader(folderNameInsideZip + "/");
log.info("文件夹在zip文件中的FileHeader:" + folderHeader);

// 如果zip文件中指定目录不存在,则创建,这一步判断是必须的,不然会导致下一次文件添加动作会覆盖之前的文件
if (Objects.isNull(folderHeader)) {
new File(folderNameInsideZip).mkdirs(); // 创建文件夹
ZipParameters folderPar = new ZipParameters();
folderPar.setCompressionLevel(CompressionLevel.NORMAL);
folderPar.setEncryptFiles(false);
zipFile.addFolder(new File(folderNameInsideZip), folderPar);
log.info("文件夹已成功添加到zip文件中。");
}

// 创建ZipParameters对象,用于设置添加文件的参数
ZipParameters parameters = new ZipParameters();
// 设置压缩方法,这里使用默认压缩方法
parameters.setCompressionMethod(CompressionMethod.DEFLATE);
// 设置压缩级别,这里使用默认压缩级别
parameters.setCompressionLevel(CompressionLevel.NORMAL);
// 设置添加文件在zip文件中的路径,格式为 "文件夹名/文件名"
parameters.setFileNameInZip(folderNameInsideZip + "/" + file.getName());

// 将文件添加到zip文件中的指定文件夹路径下
zipFile.addFile(file, parameters);
log.info("文件已成功添加到zip文件中的指定文件夹。");
} catch (ZipException e) {
throw new RuntimeException(e);
}
}
}

return zipFile.getFile().getAbsolutePath();
}

上面代码运行完毕,就会在d:/filename.zip的位置存在一个 zip 文件,打开后会看到目录结构和文件信息。接下来就需要前端来下载这个 zip 文件,我这里建立下载后就删除这个 zip 文件,这样下次重新生成时就不会出现文件合并的问题。后端下载代码如下:

`/**

File file = new File(zipFilePath);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));

return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=sample.zip")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.body(resource);

}

前段代码如下:

export function downloadCenterZip(ids) { return request({ url:/system/download/center/downloadZip`,
method: 'post',
data: ids,
responseType: 'blob' // 标识返回类型为blob
})
}

`/**

总结

对于其他格式文件的下载,其实思路都差不多,后端都需要返回一个blob或者byte数组,然后前端使用超链接的方式来触发下载。

上一篇 下一篇

猜你喜欢

热点阅读