如何在不使用 Java 保存到磁盘的情况下生成 zip 文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18406148/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:19:33  来源:igfitidea点击:

How can I generate zip file without saving to the disk with Java?

java

提问by user1198289

I have generated many BufferedImages in memory and I want to compress them into one zip file before sending it as a email attachment. How do I save the files to a zip without reading files from disk.

我在内存中生成了许多 BufferedImages,我想在将它们作为电子邮件附件发送之前将它们压缩成一个 zip 文件。如何在不从磁盘读取文件的情况下将文件保存为 zip。

Is there any way I can compress those files without creating a temp file ?

有什么办法可以在不创建临时文件的情况下压缩这些文件?

Writing to disk is time consuming due to thousands of files being created.

由于要创建数千个文件,写入磁盘非常耗时。

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cccprog;

import java.awt.Component;
import java.awt.Panel;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JRadioButton;

/**
 *
 * @author Z
 */
public class N {

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10; i++) {
            JFrame jf = new JFrame();
            Panel a = new Panel();

            JRadioButton birdButton = new JRadioButton();
            birdButton.setSize(100, 100);

            birdButton.setSelected(true);
            jf.add(birdButton);

            getSaveSnapShot(birdButton, i + ".bmp");

        }
    }

    public static BufferedImage getScreenShot(Component component) {

        BufferedImage image = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        // paints into image's Graphics
        component.paint(image.getGraphics());
        return image;
    }

    public static void getSaveSnapShot(Component component, String fileName) throws Exception {
        BufferedImage img = getScreenShot(component);
//        BufferedImage img = new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_BYTE_BINARY);

        // write the captured image as a bmp
        ImageIO.write(img, "bmp", new File(fileName));
    }
}

采纳答案by Steinar

I'm not sure about the use-case you're having here, if you have thousands of files in memory you might run out of memory rather quickly.

我不确定您在这里的用例,如果您的内存中有数千个文件,您可能会很快耗尽内存。

However, zip files are typically generated with streams anyway, so there's no need to temporarily store them in a file - might as well be in memory or streamed directly to a remote recipient (with only a small memory buffer to avoid a large memory footprint).

但是,无论如何,zip 文件通常都是使用流生成的,因此无需将它们临时存储在文件中 - 也可以在内存中或直接流式传输到远程收件人(只有很小的内存缓冲区以避免占用大量内存) .

I found an old zip utility written years ago and modified it slightly for your use-case. It creates a zip file stored in a byte array from a list of files, also stored in byte arrays. Since you have a lot of files represented in memory, I added a small helper class MemoryFilewith just the filename and a byte array containing the contents. Oh, and I made the fields public to avoid the boilerplate getter/setter stuff - just to save some space here of course.

我找到了一个多年前编写的旧 zip 实用程序,并针对您的用例对其进行了稍微修改。它从文件列表创建一个存储在字节数组中的 zip 文件,文件列表也存储在字节数组中。由于内存中存在大量文件,因此我添加了一个小助手类,MemoryFile其中仅包含文件名和包含内容的字节数组。哦,我公开了字段以避免样板 getter/setter 东西 - 当然只是为了节省一些空间。

public class MyZip {

    public static class MemoryFile {
        public String fileName;
        public byte[] contents;
    }

    public byte[] createZipByteArray(List<MemoryFile> memoryFiles) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
        try {
            for (MemoryFile memoryFile : memoryFiles) {
                ZipEntry zipEntry = new ZipEntry(memoryFile.fileName);
                zipOutputStream.putNextEntry(zipEntry);
                zipOutputStream.write(memoryFile.contents);
                zipOutputStream.closeEntry();
            }
        } finally {
            zipOutputStream.close();
        }
        return byteArrayOutputStream.toByteArray();
    }

}

回答by Terry Li

             FileInputStream[] ins = //I assume you have all file handles in the form of FileInputStream
             String[] fileNames = //I assume you have all file names
             FileOutputStream out = new FileOutputStream(""); //specify the zip file name here
             ZipOutputStream zipOut = new ZipOutputStream(out);
             for (int i=0; i<ins.length; i++) {
                 ZipEntry entry = new ZipEntry(fileNames[i]);
                 zipOut.putNextEntry(entry);
                 int number = 0;
                 byte[] buffer = new byte[512];
                 while ((number = ins[i].read(buffer)) != -1) {
                     zipOut.write(buffer, 0, number);
                 }                           
                 ins[i].close();
             }
             out.close();
             zipOut.close();

Based on the information you have provided, I come up with the code above. Hope this helps.

根据您提供的信息,我想出了上面的代码。希望这可以帮助。