在play框架中下载动态创建的zip文件

时间:2017-03-24 19:27:50

标签: java playframework stream playframework-2.0 zip

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

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

  1. 而不是$attributes = array( 'data-href' => 'http://example.com', 'data-width' => '300', 'data-height' => '250', 'data-type' => 'cover', ); $args = ""; array_walk( $attributes, function ($item, $key) use (&$args) { $args .= $key ." = '" . $item . "' "; } ); // output: 'data-href="http://example.com" data-width="300" data-height="250" data-type="cover" , 使用return ok(baos.toByteArray())

  2. 而不是逐字节读取文件,Ok.chunked(StreamConverters.fromInputStream(fileByteData))在这里非常有帮助。

  3. 附件是我的代码的完整版本。

    FileUtils.readFileToByteArray(file)