最近项目中碰到一个需求,需要点击一个按钮将不同来源的文件在服务端统一压缩成一个压缩包提供给用户下载,以下是我操作的方案
库使用的是java自带的util.zip
以下是实际将文件转换为zip的代码
/**
* @author: dejavu0716
* @create: 2023-10-13 10:56
* @Description: 压缩文件工具类
*/
public class ZipUtils {
// 传入多个文件 压缩成zip压缩包返回
public static ByteArrayOutputStream convertZip(List<InputStream> fileList, List<String> fileNameList) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
for (int i = 0; i < fileList.size(); i++) {
try (InputStream fis = fileList.get(i)) {
String nowZipEntryName = fileNameList.get(i);
ZipEntry zipEntry = new ZipEntry(nowZipEntryName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
}
}
System.out.println("zip success");
} catch (IOException e) {
e.printStackTrace();
}
return outputStream;
}
}
这里传入的参数List<InputStream> fileList, List<String> fileNameList,第一个是文件流,第二个是文件名称,可以合并成一个参数map用来存储文件和名称,我这里分开是根据项目的实际需求
同时使用了java1.7引入的try-with-resources机制,它可以将try()括号中的内容自行关闭,使得代码更加简洁,如果try()里面有多个资源,需要用分号分开,资源的close方法的调用顺序与它们的创建顺序相反
将功能代码结合业务类
public Response filesToZip(HttpServletResponse response) {
/**
*
* 动态获取需要下载压缩的相关文件
* 根据不同的文件类型做不同处理
*
**/
// 分别获取文件 添加到文件列表里面
List<InputStream> fileList = new ArrayList<>();
// 文件名放到 文件名列表里面 下标保持和文件列表对应
List<String> fileNameList = new ArrayList<>();
// *******************全路径的*******************
// 1.文件是通过链接直接获取的
String file_to_http = "https://xxxxxxxxxxxxxxxxxxxx";// 全路径 此处应为动态替换成需要的内容
List<String> urlList = new ArrayList<>();
if (file_to_http != null && !"".equals(file_to_http)) {// 实际业务流程需要判空
urlList.add(file_to_http);
}
InputStream inputStream = null;
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
OutputStream outputStream = null;
try {
for (String url_String : urlList) {
// 获取文件名
int i = url_String.lastIndexOf("/");
String fileName = url_String.substring(i + 1);
// 创建URL对象
URL url = new URL(url_String);
inputStream = url.openStream();
fileList.add(inputStream);
fileNameList.add(fileName);
}
// *******************文件id的*******************
// 2.文件是通过文件id去oss服务器上下载的
String file_to_oss = "文件id";// 文件id
if (file_to_oss != null && !"".equals(file_to_oss)) {// 实际业务流程需要判空
Map<String, ByteArrayOutputStream> file_to_ossMap = ossUploadService.getOSSfileStream(file_to_oss); // 走oss的下载接口 工具类 返回一个字节输出流
for (String fileName : file_to_ossMap.keySet()) {
// ByteArrayOutputStream
bos = file_to_ossMap.get(fileName);
// ByteArrayInputStream
bis = new ByteArrayInputStream(bos.toByteArray()); // 将字节输出流转换为字节输入流以供后续使用
fileList.add(bis);
fileNameList.add(fileName);
}
}
byte[] byteArray = null; // 此处的byteArray是用来将最后压缩的压缩文件流传递给前端下载
try (ByteArrayOutputStream byteArrayOutputStream = ZipUtils.convertZip(fileList, fileNameList)) { // 通过功能接口获取压缩后的压缩文件流
byteArray = byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
if (byteArray != null) {
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("压缩文件名称.zip", "UTF-8"));
response.setContentLength(byteArray.length);
outputStream = response.getOutputStream();
outputStream.write(byteArray);
outputStream.flush();
}
return new Response(true, MessageConstant.DOWNLOAD_SUCCEEDED, null, "200");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (inputStream != null) {
inputStream.close();
}
if (bos != null) {
bos.close();
}
if (bis != null) {
bis.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
System.err.println("********关闭流出现异常********");
e.printStackTrace();
}
}
return new Response(false, MessageConstant.DOWNLOAD_FAIL, null, "500"); // 自定义的返回对象类
}
代码中都有注释,这里就不过多阐述了,需要注意的是各种流之间的转换,最后务必记得关闭即可。