简体   繁体   English

Java - try-with-resources 中的 ZipOutputStream

[英]Java - ZipOutputStream within try-with-resources

I have this Java code that creates and saves a zip file with a text file inside it:我有这个 Java 代码,它创建并保存一个 zip 文件,里面有一个文本文件:

public static void main(String[] args) {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ZipOutputStream zos = new ZipOutputStream(baos)) {
        String s = "Hello, world!";
        ZipEntry entry = new ZipEntry("text_file.txt");
        zos.putNextEntry(entry);
        zos.write(s.getBytes());
        zos.closeEntry();

        try (OutputStream os = new FileOutputStream("zip_file.zip")) {
            baos.writeTo(os);
            System.out.println("ZIP file created successfully");
        }
    } catch (IOException e) {
        System.out.println("Error: " + e);
    }
}

The problem with this code is that it creates a zip file that is corrupted, so I cannot extract or even open the content within it.此代码的问题在于它创建了一个损坏的 zip 文件,因此我无法提取甚至打开其中的内容。

Eventually I found out that if I manually close the ZipOutputStream by putting zos.close() after zos.closeEntry() the zip file is created successfully without corruption.最终我发现,如果我通过在zos.close()之后放置 zos.close( zos.closeEntry()手动关闭ZipOutputStream ,则 zip 文件将成功创建而不会损坏。 Honestly this does not make any sense to me since I have declared the ZipOutputStream inside a try-with-resource statement, so I would have expected it to close automatically.老实说,这对我来说没有任何意义,因为我已经在try-with-resource语句中声明了ZipOutputStream ,所以我希望它会自动关闭。

So it seems that the try-with-resource statement does not actually close the stream. Am I doing something wrong?所以看起来try-with-resource语句实际上并没有关闭stream。我做错了吗?

Any help would be appreciated.任何帮助,将不胜感激。

OS: Windows 10操作系统:Windows 10

Note: I used ByteArrayOutputStream because in the real scenario I have to create the zip file in memory, since I don't have a folder on a disk to rely on.注意:我使用ByteArrayOutputStream是因为在实际场景中我必须在 memory 中创建 zip 文件,因为我在磁盘上没有可依赖的文件夹。

The try-with-resources does close the ZipOutputStream . try-with-resources确实关闭了ZipOutputStream It's just that it closes the zip stream after you copy its content to the FileOutputStream .只是在将其内容复制到FileOutputStream后,它会关闭 zip stream 。 How do you expect work that happens after the file has been closed to affect the content of the file?您期望文件关闭后发生的工作如何影响文件的内容?

I recommend replacing the ByteArrayOutputStream with the FileOutputStream .我建议将ByteArrayOutputStream替换为FileOutputStream What need do you have to buffer?你有什么需要缓冲的?

try (OutputStream os = new FileOutputStream("zip_file.zip");
     ZipOutputStream zos = new ZipOutputStream(os)) {
  String s = "Hello, world!";
  ZipEntry entry = new ZipEntry("text_file.txt");
  zos.putNextEntry(entry);
  zos.write(s.getBytes());
  zos.closeEntry();
}
System.out.println("ZIP file created successfully");

It turned out that I was misplacing the ByteArrayOutputStream object: I should have not closed it by placing it inside the try-with-resource statement because, as explained here , ByteArrayOutputStream is purely memory based so the allocated memory will be released automatically by the garbage collector.事实证明,我放错了ByteArrayOutputStream object:我不应该通过将它放在 try-with-resource 语句中来关闭它,因为如此所述, ByteArrayOutputStream纯粹基于 memory,因此分配的 memory 将由垃圾自动释放集电极。

The following code produces the desired result:以下代码产生所需的结果:

public static void main(String[] args) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    try (ZipOutputStream zos = new ZipOutputStream(baos)) {
        String s = "Hello, world!";
        ZipEntry entry = new ZipEntry("text_file.txt");
        zos.putNextEntry(entry);
        zos.write(s.getBytes());
        zos.closeEntry();
    } catch (IOException e) {
        System.out.println("Error: " + e);
    }

    try (OutputStream os = new FileOutputStream("zip_file.zip")) {
        baos.writeTo(os);
        System.out.println("ZIP file created successfully");
    } catch (IOException e) {
        System.out.println("Error: " + e);
    }
}

To keep everything in same Try-catch, another approach is to finish & flush the ZipOutputStream before using the content of ByteArrayOutputStream inside it (which can be incomplete, this is why it may generate corrupted zip), for example:为了将所有内容保持在相同的 Try-catch 中,另一种方法是在使用其中的 ByteArrayOutputStream 内容之前完成并刷新 ZipOutputStream (这可能是不完整的,这就是它可能生成损坏的 zip 的原因),例如:

 try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ZipOutputStream zos = new ZipOutputStream(baos)) {
    //codes insert into zip
    zos.finish(); //finish writing
    zos.flush(); //flush any buffer inside
    //use baos 
 } catch (IOException e) {
    System.out.println("Error: " + e);
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM