【问题标题】:create zip file without writing to disk创建 zip 文件而不写入磁盘
【发布时间】:2019-07-23 06:44:28
【问题描述】:

我正在开发一个 Springboot 应用程序,当用户下载一些报告时,它必须将一个 zip 文件返回到前端。我想创建一个 zip 文件而不将 zip 文件或原始文件写入磁盘。

我要压缩的目录包含其他包含实际文件的目录。比如dir1里面有subDir1和subDir2,subDir1会有两个文件subDir1File1.pdf和subDir1File2.pdf。 subDir2 里面也有文件。

我可以通过在磁盘上创建物理文件轻松做到这一点。但是,我觉得在不写入磁盘的情况下返回这些文件会更优雅。

【问题讨论】:

    标签: java java-io


    【解决方案1】:

    如果作用域是写入内存,您将使用ByteArrayOutputStream。从本质上讲,zip 文件将完全包含在内存中,因此请确保您不会冒一次有太多请求的风险,并且文件大小是合理的!否则这种方法可能会适得其反!

    【讨论】:

      【解决方案2】:

      您可以使用以下 sn-p :

      public static byte[] zip(final String str) throws IOException {
      
              if (StringUtils.isEmpty(str)) {
                  throw new IllegalArgumentException("Cannot zip null or empty string");
              }
      
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              try (GZIPOutputStream gos = new GZIPOutputStream(bos)) {
                  gos.write(str.getBytes(StandardCharsets.UTF_8));
              }
              return bos.toByteArray();
      
          }
      

      但正如另一个答案中所述,通过将所有内容加载到您的 java 内存中,确保您不会给程序带来太大风险。

      【讨论】:

        【解决方案3】:

        请注意,您应该尽可能流式传输。在您的情况下,您可以将数据写入https://docs.oracle.com/javase/8/docs/api/index.html?java/util/zip/ZipOutputStream.html

        此方法的唯一缺点是:客户端将无法显示下载状态栏,因为服务器将无法发送“Content-length”标头。这是因为 ZIP 文件的大小只有在生成后才能知道,但服务器需要先发送标头。所以 - 没有临时 zip 文件 - 事先没有文件大小。

        您也在谈论子目录。这只是处理 ZIP 流时的命名问题。每个 zip 项目都需要这样命名:“directory/directory2/file.txt”。这会在解压时产生子目录。

        【讨论】:

        • 我尝试了这个解决方案,但我遇到了另一个问题。我可以压缩文件并返回一个压缩文件夹,这很好。但是压缩后的文件夹里面什么都没有,更准确地说,当我尝试解压缩时会抛出错误。你知道为什么会这样吗?
        • 您的文件名是用纯 ASCII 编码的吗?其他编码似乎一直是问题的根源...superuser.com/questions/1321371/…
        猜你喜欢
        • 2011-05-09
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多