如何在Java中生成zip文件而无需保存到磁盘?

18

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

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

由于创建了成千上万个文件,写入磁盘非常耗时。

/*
 * 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));
    }
}

4
看看 java.util.zip。 - Hot Licks
1
只是出于好奇,你为什么要避免创建临时文件? - user784540
这似乎与此相关:https://dev59.com/MFrUa4cB1Zd3GeqPjWWI - Ted
你可以将数据写入流而不是文件,但你仍然需要能够读取原始文件数据。不过,我认为源文件也可以是一个流。 - Ted
你在内存中引用那些PDF文件时使用了什么类型的文件句柄?是File还是FileInputStream? - Terry Li
请查看以下两个答案:https://dev59.com/lm025IYBdhLWcg3wkGx7 和 https://dev59.com/22ct5IYBdhLWcg3whtuh。祝好运! - esmoreno
2个回答

27

关于你在这里使用的用例,我不太确定。如果你在内存中有成千上万个文件,你可能会很快耗尽内存。

但是,zip文件通常是使用流生成的,因此没有必要将它们暂时存储在文件中 - 它们可以直接保存在内存中或直接流式传输到远程收件人(只需使用一个小内存缓冲区以避免大内存占用)。

我找到了一款几年前编写的旧的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();
    }

}

我更新了我的原始帖子。我对如何使用BufferImage来实现相同的功能感到困惑。 - user1198289
2
你不仅仅“更新”了原帖,而是完全改变了它。我并不是特别喜欢这样做;也就是说,在我花时间回答问题之后,问题完全改变了。你应该意识到,在内存中拥有“成千上万”的PDF和成千上万的BufferedImage是两码事。对于每个图像,你需要获得所需格式(gif、png、jpg等)的输出流,以便保存/传输它们。另外请注意,压缩图像在压缩方面几乎没有效果,因为它们通常已经被压缩过了。 - Steinar

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

根据您提供的信息,我编写了上述代码。希望这可以帮到您。

我更新了原始帖子。我困惑如何使用BufferImage来完成相同的操作。 - user1198289

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接