java - Vertx 将 zip 文件流式传输到 http 响应
问题描述
我正在尝试流式传输一个 zip 文件作为输出供用户下载。我创建了一个 zipOutputStream,并尝试将其发送到 vertx http 响应中。
但是,这会下载损坏的 zip 文件或挂起
public void download(RoutingContext routingContext) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < 2; i++) {
String fileName = "test" + i + ".csv";
File tempFile = createTempFile("test" + i);
tempFile.deleteOnExit();
InputStream is = new FileInputStream(tempFile);
byte[] buffer = new byte[is.available()];
is.read(buffer);
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
try {
zos.write(buffer, 0, buffer.length);
zos.closeEntry();
String b64String = Base64.encodeBase64String(baos.toByteArray());
routingContext.response()
.setChunked(true)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/zip")
.putHeader("Content-Disposition", "attachment; filename=\"test.zip\"")
.putHeader(HttpHeaders.TRANSFER_ENCODING, "chunked")
.putHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(b64String.length()));
routingContext.response().write(b64String);
routingContext.response().end();
routingContext.response().close();
} finally {
baos.close();
}
}
}
catch(Exception ex) {
}
}
解决方案
对于非常大的文件,您可以使用流式传输来避免将它们完全加载到 RAM 中:
AsyncInputStream fileContent = new AsyncInputStream(routingContext.vertx(), fileInputStream);
fileContent.endHandler((ev) -> {
routingContext.response().end();
});
Pump.pump(fileContent, routingContext.response()).start();
不幸的是,AsyncInputStream(InputStream 到 ReadStream 的包装器)还不是 VertX 框架的一部分,因此您必须自己实现它或找到一些开源实现。
推荐阅读
- linux - 重启后 binfmt_misc 的设置消失了
- arrays - 根据多个条件对哈希数组进行排序和重新排列
- bash - 在bash中查找所有以扩展名结尾的文件
- scala - Scala错误类型子类型的表达式不符合预期的类型T
- c# - 在 c# 中的 ssh.net 下命令未完全执行
- python - 如何根据有序列表替换熊猫数据框列中的元素?
- mysql - MySQL比较两个结果并显示增量
- python - 在 Python 中使用文件获取所有进程
- ruby-on-rails - 为什么 ruby REGEX \A...\z 允许在开始时输入任何内容?
- amazon-web-services - AWS 资源(Lambda 和 API 网关)之间传输中的加密