编写 BufferedImage 缓存并将其保存到磁盘
Writing a BufferedImage cache and save it to disk
我正在开发一个 java
应用程序,我在其中加载了一些包含图像(从网络下载)的长列表,因此我添加了一个快速 HashMap<String,BufferedImage>
作为缓存,以避免重新下载相同的图像图像多次。
这工作正常,应用程序速度更快,但让这个缓存在各种会话中持续存在会很好,所以我将缓存更改为序列化。
BufferedImage
不是 Serializable
,所以我不得不写我的自定义方法。
我的文件结构应该是这样的:
- (int) 元素数
- [(URL) 图片的键值
- (Object)图像使用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);
}
}
错误发生是因为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;
}
我正在开发一个 java
应用程序,我在其中加载了一些包含图像(从网络下载)的长列表,因此我添加了一个快速 HashMap<String,BufferedImage>
作为缓存,以避免重新下载相同的图像图像多次。
这工作正常,应用程序速度更快,但让这个缓存在各种会话中持续存在会很好,所以我将缓存更改为序列化。
BufferedImage
不是 Serializable
,所以我不得不写我的自定义方法。
我的文件结构应该是这样的:
- (int) 元素数
- [(URL) 图片的键值
- (Object)图像使用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);
}
}
错误发生是因为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;
}