English 中文(简体)
JaxRS 从服务器创建并返回 zip 文件
原标题:JaxRS create and return zip file from server
  • 时间:2012-05-26 02:52:08
  •  标签:
  • java
  • jax-rs

我想使用 JaxRS 从服务器上创建并返回一个 zip 文件 。 我不认为我想在服务器上创建一个真实的文件, 如果可能的话, 我想在苍蝇上创建一个 zip, 并将它转回客户端 。 如果我在苍蝇上创建了一个巨大的 zip 文件, 如果我在 izp 文件中出现太多的文件, 我将会失去记忆?

我也不确定最有效的方法。 这就是我在想的,但对于Java的投入/产出,我非常生锈。

public Response getFiles() {

// These are the files to include in the ZIP file       
String[] filenames = // ... bunch of filenames

byte[] buf = new byte[1024];

try {
   // Create the ZIP file
   ByteArrayOutputStream baos= new ByteArrayOutputStream();
   ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(baos));

   // Compress the files
   for (String filename : filenames) {
       FileInputStream in = new FileInputStream(filename);

       // Add ZIP entry to output stream.
       out.putNextEntry(new ZipEntry(filename));

       // Transfer bytes from the file to the ZIP file
       int len;
       while ((len = in.read(buf)) > 0) {
         out.write(buf, 0, len);
       }
       // Complete the entry
       out.closeEntry();
       in.close();
   }

   // Complete the ZIP file
   out.close();

   ResponseBuilder response = Response.ok(out);  // Not a 100% sure this will work
   response.type(MediaType.APPLICATION_OCTET_STREAM);
   response.header("Content-Disposition", "attachment; filename="files.zip"");
   return response.build();

} catch (IOException e) {       
}

}

如有任何帮助,将不胜感激。

最佳回答

有两个选项:

1 - 在时间目录中创建 ZIP, 然后倾弃到客户端 。

2- 使用响应中的输出键直接发送到客户端, 当您正在创建它们时 。

但永远不要用内存来创建巨大的 ZIP 文件 。

问题回答

s 无需在向客户端提供服务之前先在存储器中从第一个字节到最后一个字节创建 ZIP 文件。此外,也无需提前在临时目录中创建这样的文件(特别是因为IO可能非常慢 ) 。

关键是开始流出“ ZIP 响应” 并生成飞行内容 。

假设我们有一个 a MethodReturningStream > () , 返回一个 Stream , 我们想要将每个元素转换成一个存储在 ZIP 文件的文件。 而我们不想保存每个元素的字节, 像收藏或数组一样, 。

那么这种假编码也许有帮助:

@GET
@Produces("application/zip")
public Response generateZipOnTheFly() {
    StreamingOutput output = strOut -> {
        try (ZipOutputStream zout = new ZipOutputStream(strOut)) {
            aMethodReturningStream().forEach(singleStreamElement -> {
                try {
                    ZipEntry zipEntry = new ZipEntry(createFileName(singleStreamElement));
                    FileTime fileTime = FileTime.from(singleStreamElement.getCreationTime());
                    zipEntry.setCreationTime(fileTime);
                    zipEntry.setLastModifiedTime(fileTime);
                    zout.putNextEntry(zipEntry);
                    zout.write(singleStreamElement.getBytes());
                    zout.flush();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    };
    return Response.ok(output)
                   .header("Content-Disposition", "attachment; filename="generated.zip"")
                   .build();
}

This concept relies on passing a StreamingOutput to the Response builder. The StreamingOutput is not a full response/entity/body generated before sending the response, but a recipe used to generate the flow of bytes on-the-fly (here wrapped into ZipOutputStream). If you re not sure about this, then maybe set a breakpoint next on flush() and observe the a download progress using e.g. wget. The key thing to remember here is that the stream here is not a "wrapper" of pre-computed or pre-fetched items. It must be dynamic, e.g. wrapping a DB cursor or something like that. Also, it can be replaced by anything that s streaming data. That s why it cannot be a foreach loop iterating over Element[] elems array (with each Element having all the bytes "inside"), like

for(Element elem: elems)

如果您想要避免同时读取堆积中的所有项目, 请在 < / em > 流出 ZIP 前的 < em > 。

(请注意,这是一个假代码,你可能还要加上更好的处理和擦亮其它东西。 )





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签