18

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.

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));
    }
}
Mayank
  • 8,777
  • 4
  • 35
  • 60
user1198289
  • 637
  • 1
  • 5
  • 14
  • 4
    Look at java.utli.zip. – Hot Licks Aug 23 '13 at 15:09
  • 1
    Just for my curiosity, why do you want to avoid creating a temp file? –  Aug 23 '13 at 15:09
  • This seems related http://stackoverflow.com/questions/7108035/how-to-flush-the-zipoutputstream-periodically-in-java – Ted Aug 23 '13 at 15:17
  • You can write to a stream instead of a file, but you will always have to be able to read the original file data. However, I think the source files can be a stream as well. – Ted Aug 23 '13 at 15:21
  • What kind of file handle are you using to refer to those pdf files in memory? File? FileInputStream? – Terry Li Aug 23 '13 at 15:29
  • See this two answers: http://stackoverflow.com/questions/5934495/implementing-in-memory-compression-for-objects-in-java and http://stackoverflow.com/questions/12030703/uncompressing-a-zip-file-in-memory-in-java Good Luck! – esmoreno Aug 23 '13 at 15:49

2 Answers2

27

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).

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 MemoryFile with 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.

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

}
Steinar
  • 5,860
  • 1
  • 25
  • 23
  • I updated my original post. I was confused how a BufferImage could be used to do the same. – user1198289 Aug 23 '13 at 20:48
  • 2
    You've not only "updated" your original post, you've totally changed it. I'm not overly fond of that; i.e. that the question is totally changed after I've spent time answering it. You should be aware that having "thousands" of PDF's in memory and thousands of BufferedImages are two different things. For each image, tou'll need to obtain an output stream in the format (gif, png, jpg, etc.) that you like to save/transfer them in. Also note that zipping images have little effect in terms of compression, since they are usually already compressed. – Steinar Aug 24 '13 at 15:56
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();

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

Terry Li
  • 16,870
  • 30
  • 89
  • 134