在播放框架中下载动态创建的 zip 文件
Download dynamically created zip files in play framework
您好,我正在尝试编写一个可以下载多个文件的播放框架服务。我即时创建了多个文件的 zip,但我不确定如何在 Play Framework 中将其作为响应发送我将展示我到目前为止所做的事情。
public Result download() {
String[] items = request().queryString().get("items[]");
String toFilename = request().getQueryString("toFilename");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(baos))) {
for (String item : items) {
Path path = Paths.get(REPOSITORY_BASE_PATH, item);
if (Files.exists(path)) {
ZipEntry zipEntry = new ZipEntry(path.getFileName().toString());
zos.putNextEntry(zipEntry);
byte buffer[] = new byte[2048];
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path))) {
int bytesRead = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
} finally {
zos.closeEntry();
}
}
}
response().setHeader("Content-Type", "application/zip");
response().setHeader("Content-Disposition", "inline; filename=\"" + MimeUtility.encodeWord(toFilename) + "\"");
//I am confused here how to output the response of zip file i have created
//I tried with the `baos` and with `zos` streams but not working
return ok(baos.toByteArray());
} catch (IOException e) {
LOG.error("copy:" + e.getMessage(), e);
return ok(error(e.getMessage()).toJSONString());
}
return null;
}
我尝试用 return ok(baos.toByteArray());
发送响应我能够下载文件但是当我打开下载的文件时它给我错误 An error occurred while loading the archive
。
您需要关闭 zip 文件。添加所有条目后,执行:zos.close()
附带说明一下,我建议将 zip 文件写入磁盘而不是将其保存在内存缓冲区中。然后,您可以使用 return ok(File content, String filename)
将其内容发送到客户端。
如果有人想知道最终代码是什么,我将添加这个答案:
String[] items = request().queryString().get("items[]");
String toFilename = request().getQueryString("toFilename");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(baos))) {
for (String item : items) {
Path path = Paths.get(REPOSITORY_BASE_PATH, item);
if (Files.exists(path)) {
ZipEntry zipEntry = new ZipEntry(path.getFileName().toString());
zos.putNextEntry(zipEntry);
byte buffer[] = new byte[2048];
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path))) {
int bytesRead = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
} finally {
zos.closeEntry();
}
}
}
zos.close(); //closing the Zip
response().setHeader("Content-Type", "application/zip");
response().setHeader("Content-Disposition", "attachment; filename=\"" + MimeUtility.encodeWord(toFilename) + "\"");
return ok(baos.toByteArray());
} catch (IOException e) {
LOG.error("copy:" + e.getMessage(), e);
return ok(error(e.getMessage()).toJSONString());
}
感谢您的帮助!我做了两个额外的更改,因此它适用于 scala playframework 2。5.x
而不是 return ok(baos.toByteArray())
,
使用 Ok.chunked(StreamConverters.fromInputStream(fileByteData))
无需逐字节读取文件,FileUtils.readFileToByteArray(file)
在这里很有用。
附件是我的代码的完整版本。
import java.io.{BufferedOutputStream, ByteArrayInputStream, ByteArrayOutputStream}
import java.util.zip.{ZipEntry, ZipOutputStream}
import akka.stream.scaladsl.{StreamConverters}
import org.apache.commons.io.FileUtils
import play.api.mvc.{Action, Controller}
class HomeController extends Controller {
def single() = Action {
Ok.sendFile(
content = new java.io.File("C:\Users\a.csv"),
fileName = _ => "a.csv"
)
}
def zip() = Action {
Ok.chunked(StreamConverters.fromInputStream(fileByteData)).withHeaders(
CONTENT_TYPE -> "application/zip",
CONTENT_DISPOSITION -> s"attachment; filename = test.zip"
)
}
def fileByteData(): ByteArrayInputStream = {
val fileList = List(
new java.io.File("C:\Users\a.csv"),
new java.io.File("C:\Users\b.csv")
)
val baos = new ByteArrayOutputStream()
val zos = new ZipOutputStream(new BufferedOutputStream(baos))
try {
fileList.map(file => {
zos.putNextEntry(new ZipEntry(file.toPath.getFileName.toString))
zos.write(FileUtils.readFileToByteArray(file))
zos.closeEntry()
})
} finally {
zos.close()
}
new ByteArrayInputStream(baos.toByteArray)
}
}
您好,我正在尝试编写一个可以下载多个文件的播放框架服务。我即时创建了多个文件的 zip,但我不确定如何在 Play Framework 中将其作为响应发送我将展示我到目前为止所做的事情。
public Result download() {
String[] items = request().queryString().get("items[]");
String toFilename = request().getQueryString("toFilename");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(baos))) {
for (String item : items) {
Path path = Paths.get(REPOSITORY_BASE_PATH, item);
if (Files.exists(path)) {
ZipEntry zipEntry = new ZipEntry(path.getFileName().toString());
zos.putNextEntry(zipEntry);
byte buffer[] = new byte[2048];
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path))) {
int bytesRead = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
} finally {
zos.closeEntry();
}
}
}
response().setHeader("Content-Type", "application/zip");
response().setHeader("Content-Disposition", "inline; filename=\"" + MimeUtility.encodeWord(toFilename) + "\"");
//I am confused here how to output the response of zip file i have created
//I tried with the `baos` and with `zos` streams but not working
return ok(baos.toByteArray());
} catch (IOException e) {
LOG.error("copy:" + e.getMessage(), e);
return ok(error(e.getMessage()).toJSONString());
}
return null;
}
我尝试用 return ok(baos.toByteArray());
发送响应我能够下载文件但是当我打开下载的文件时它给我错误 An error occurred while loading the archive
。
您需要关闭 zip 文件。添加所有条目后,执行:zos.close()
附带说明一下,我建议将 zip 文件写入磁盘而不是将其保存在内存缓冲区中。然后,您可以使用 return ok(File content, String filename)
将其内容发送到客户端。
如果有人想知道最终代码是什么,我将添加这个答案:
String[] items = request().queryString().get("items[]");
String toFilename = request().getQueryString("toFilename");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(baos))) {
for (String item : items) {
Path path = Paths.get(REPOSITORY_BASE_PATH, item);
if (Files.exists(path)) {
ZipEntry zipEntry = new ZipEntry(path.getFileName().toString());
zos.putNextEntry(zipEntry);
byte buffer[] = new byte[2048];
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path))) {
int bytesRead = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
} finally {
zos.closeEntry();
}
}
}
zos.close(); //closing the Zip
response().setHeader("Content-Type", "application/zip");
response().setHeader("Content-Disposition", "attachment; filename=\"" + MimeUtility.encodeWord(toFilename) + "\"");
return ok(baos.toByteArray());
} catch (IOException e) {
LOG.error("copy:" + e.getMessage(), e);
return ok(error(e.getMessage()).toJSONString());
}
感谢您的帮助!我做了两个额外的更改,因此它适用于 scala playframework 2。5.x
而不是
return ok(baos.toByteArray())
, 使用Ok.chunked(StreamConverters.fromInputStream(fileByteData))
无需逐字节读取文件,
FileUtils.readFileToByteArray(file)
在这里很有用。
附件是我的代码的完整版本。
import java.io.{BufferedOutputStream, ByteArrayInputStream, ByteArrayOutputStream}
import java.util.zip.{ZipEntry, ZipOutputStream}
import akka.stream.scaladsl.{StreamConverters}
import org.apache.commons.io.FileUtils
import play.api.mvc.{Action, Controller}
class HomeController extends Controller {
def single() = Action {
Ok.sendFile(
content = new java.io.File("C:\Users\a.csv"),
fileName = _ => "a.csv"
)
}
def zip() = Action {
Ok.chunked(StreamConverters.fromInputStream(fileByteData)).withHeaders(
CONTENT_TYPE -> "application/zip",
CONTENT_DISPOSITION -> s"attachment; filename = test.zip"
)
}
def fileByteData(): ByteArrayInputStream = {
val fileList = List(
new java.io.File("C:\Users\a.csv"),
new java.io.File("C:\Users\b.csv")
)
val baos = new ByteArrayOutputStream()
val zos = new ZipOutputStream(new BufferedOutputStream(baos))
try {
fileList.map(file => {
zos.putNextEntry(new ZipEntry(file.toPath.getFileName.toString))
zos.write(FileUtils.readFileToByteArray(file))
zos.closeEntry()
})
} finally {
zos.close()
}
new ByteArrayInputStream(baos.toByteArray)
}
}