【问题标题】:Download dynamically created zip files in play framework在播放框架中下载动态创建的 zip 文件
【发布时间】:2017-08-17 20:57:33
【问题描述】:

您好,我正在尝试编写一个可以下载多个文件的播放框架服务。我即时创建了多个文件的 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

【问题讨论】:

  • 什么不起作用?你检查过回复吗? ok 方法有几个选项来响应文件(文件,InputStream),如果你没有看到文件打开一个对话框来下载文件,你应该把它添加到你的响应中application/x-download
  • 我的意思是我可以下载文件,但是当我打开它时,我的存档管理器游戏我读取文件时出错
  • 我尝试使用return ok(baos.toByteArray()); 发送响应,文件大小似乎还可以,但是当我打开下载的文件时,它给了我错误An error occured while loading the archive.
  • 那么问题不在于播放,您在压缩文件时可能做错了。
  • 我有上面提到的邮政编码你觉得有什么问题吗?

标签: java playframework stream playframework-2.0 zip


【解决方案1】:

感谢您的帮助!我做了两个额外的更改,因此它适用于 scala playframework 2.5.x

  1. 而不是 return ok(baos.toByteArray()) , 使用Ok.chunked(StreamConverters.fromInputStream(fileByteData))

  2. 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)
  }
}

【讨论】:

    【解决方案2】:

    如果有人想知道最终代码是什么,我将添加此答案:

            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());
            }
    

    【讨论】:

      【解决方案3】:

      您需要关闭 zip 文件。添加所有条目后,执行:zos.close()

      附带说明,我建议将 zip 文件写入磁盘,而不是将其保存在内存缓冲区中。然后您可以使用return ok(File content, String filename) 将其内容发送给客户端。

      【讨论】:

      • 它工作得很好,我忘了关闭流。非常感谢你救了我的头痛:)。我同意不在内存中发送内容并通过文件发送它们,但实际上要求不要保存在磁盘中而是直接动态创建:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 1970-01-01
      • 2011-01-16
      相关资源
      最近更新 更多