编写BufferedImage缓存并将其保存到磁盘

时间:2015-06-04 13:00:48

标签: java caching serialization bufferedimage

我正在开发一个java应用程序,我在其中加载一些包含图像的长列表(从web下载),因此我添加了一个快速HashMap<String,BufferedImage>作为缓存,以避免重新加载同一图像多个次。

这样可以正常工作并且应用程序更快,但让这个缓存在各个会话中保持不变会很好,所以我将缓存更改为序列化。

BufferedImage不是Serializable,所以我必须编写自定义方法。

我的文件结构应该是这样的:

  • (int)元素数量
  • [(URL)图片的密钥
  • 使用ImageIO写的
  • (对象)图像n次

虽然文件保存似乎很好(至少我没有例外),当我尝试加载URL它会java.io.OptionalDataException length = 4并且我不明白为什么。第一次迭代很顺利,但是一旦我尝试加载第二个URL,我就会遇到这个异常,所以我怀疑加载第一个图像的方式有问题。

这是完整的代码:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;


public class PicturesCache {

    private static HashMap<String, BufferedImage> picturesCache;

    private static final String cacheDiskLocation = "pictures_cache.map";

    private static void writeCache(ObjectOutputStream oos, HashMap<String, BufferedImage> data) throws IOException {
        // Number of saved elements
        oos.writeInt(data.size());
        // Let's write (url, image) for each entry in the cache
        for (Entry<String, BufferedImage> entry : data.entrySet()) {   
            oos.writeObject(new URL(entry.getKey()));
            ImageIO.write(entry.getValue(), "png", oos);
        }
    }

    private static HashMap<String, BufferedImage> readCache(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        // Number of saved elements
        int size = ois.readInt();
        // Cache
        HashMap<String, BufferedImage> result = new HashMap<>(size);
        // Let's read (url, image) and add them to cache
        for (int i = 0; i < size; i++) {
            String url = ((URL) ois.readObject()).toString(); // EXCEPTION HERE
            BufferedImage image = ImageIO.read(ois);            
            result.put(url, image);
        }
        return result;
    }

    public static void loadCache() {
        picturesCache = new HashMap<>();
        File file = new File(cacheDiskLocation);
        if (file.isFile()) {
            FileInputStream fis = null;
            ObjectInputStream ois = null;
            try {
                fis = new FileInputStream(file);
                ois = new ObjectInputStream(fis);
                picturesCache = readCache(ois);
            } catch (IOException | ClassNotFoundException ex) {
                Logger.getLogger(PicturesCache.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    ois.close();
                    fis.close();
                } catch (IOException ex) {
                    Logger.getLogger(PicturesCache.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        System.out.println("Cache loaded with " + picturesCache.size() + " elements");
    }

    public static void saveCache() {
        File file = new File(cacheDiskLocation);
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try {
            if (file.isFile()) {
                file.delete();
            }
            file.createNewFile();
            fos = new FileOutputStream(file);
            oos = new ObjectOutputStream(fos);
            writeCache(oos, picturesCache);
        } catch (IOException ex) {
            Logger.getLogger(PicturesCache.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                System.out.println("Cache saved with " + picturesCache.size() + " elements");
                oos.close();
                fos.close();
            } catch (IOException ex) {
                Logger.getLogger(PicturesCache.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static boolean contains(String url) {
        return picturesCache.containsKey(url);
    }

    public static BufferedImage get(String url) {
        return picturesCache.get(url);
    }

    public static void put(String url, BufferedImage image) {
        picturesCache.put(url, image);
    }

}

1 个答案:

答案 0 :(得分:1)

发生错误是因为ImageIO.read(...)未读取使用ImageIO.write(...)编写的所有数据。您可以将图像作为ObjectOutputStread写入byte[]。例如:

private static void writeCache(ObjectOutputStream oos,
        HashMap<String, BufferedImage> data) throws IOException {
    // Number of saved elements
    oos.writeInt(data.size());
    // Let's write (url, image) for each entry in the cache
    for (Entry<String, BufferedImage> entry : data.entrySet()) {
        oos.writeObject(new URL(entry.getKey()));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(entry.getValue(), "jpg", baos);
        byte[] bytes = baos.toByteArray();
        oos.writeObject(bytes);
    }
}

private static HashMap<String, BufferedImage> readCache(
        ObjectInputStream ois) throws IOException, ClassNotFoundException {
    // Number of saved elements
    int size = ois.readInt();
    // Cache
    HashMap<String, BufferedImage> result = new HashMap<>(size);
    // Let's read (url, image) and add them to cache
    for (int i = 0; i < size; i++) {
        String url = ((URL) ois.readObject()).toString(); // EXCEPTION HERE
        ByteArrayInputStream bais = new ByteArrayInputStream(
                (byte[]) ois.readObject());
        BufferedImage image = ImageIO.read(bais);
        result.put(url, image);
    }
    return result;
}