2015-06-04 129 views
0

我正在開發一個java應用程序,其中我加載了一些包含圖像的長列表(從網上下載),所以我添加了一個快速HashMap<String,BufferedImage>作爲緩存,以避免重新下載相同的圖像多次。編寫一個緩衝圖像緩存並將其保存到磁盤

這工作正常,應用程序的速度更快,但它會很高興讓這個緩存持續通過各種會話,所以我改變了我的緩存序列化。因此我不得不編寫我的自定義方法。

我的文件結構應該是這樣的:

  • (INT)元素的個數
  • [(URL)圖像的關鍵
  • 使用ImageIO的
  • (對象)的圖像寫入] n倍

儘管文件保存似乎很好(至少我沒有例外),當我嘗試加載URL時,它會拋出java.io.OptionalDataExceptionlength = 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); 
    } 

} 

回答

0

的錯誤,因爲ImageIO.read(...)不閱讀所有使用ImageIO.write(...)寫入的數據。您可以將圖像作爲byte[]寫入ObjectOutputStread。例如:

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; 
} 
+0

我現在不能嘗試,但我懷疑這是由於例外中顯示的數字所致。你知道爲什麼'ImageIO.read(...)'有這種奇怪的行爲嗎? – StepTNT

+1

@StepTNT我不確定,這可能是因爲用於讀取圖像的'ImageReader'沒有使用與'ImageWriter'相同的格式,或者因爲'write(...)'方法添加了一些元數據,這些元數據是不被'read(...)'方法消耗。 – Titus

+0

@StepTNT,在我的系統上,如果我使用'jpg'而不是'png',則不會發生錯誤('ImageIO.write(entry.getValue(),「jpg」,oos);')所以我猜這個問題是'ImageWriter'和'ImageReader'使用不同的格式。 – Titus