13

您好我在内存中有一个 BufferedImage 实例,出于性能考虑,我想将其转换为 byte[] 以编码为 base64 字符串而无需 I/O 操作。我正在使用以下 API:

ByteArrayOutputStream baos = new ByteArrayOutputStream ();
ImageIO.write(image,"png",baos);
return baos.toByteArray();

但是这个API还是会隐式的将镜像写入OS temp目录,这样会导致底层OS temp目录已满,无法创建temp文件的情况下失败。堆栈跟踪:

Caused by: java.io.IOException: No space left on device
    at java.io.RandomAccessFile.write(RandomAccessFile.java:493)
    at javax.imageio.stream.FileCacheImageOutputStream.write(FileCacheImageOutputStream.java:134)
    at javax.imageio.stream.ImageOutputStreamImpl.write(ImageOutputStreamImpl.java:66)
    at com.sun.imageio.plugins.png.PNGImageWriter.write_magic(PNGImageWriter.java:376)
    at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:1115)
    at javax.imageio.ImageWriter.write(ImageWriter.java:628)
    at javax.imageio.ImageIO.write(ImageIO.java:1480)
    at javax.imageio.ImageIO.write(ImageIO.java:1554)

是否有一种有效的(如内存转换或高效的 I/O)方式来进行没有 I/O 的转换?请指教。

4

4 回答 4

12

通过ImageIO.setUseCache()方法禁用 ImageIO 缓存:

ImageIO.setUseCache(false);

根据 javadoc,默认情况下它是打开的:

设置一个标志,指示在创建 ImageInputStreams 和 ImageOutputStreams 时是否应使用基于磁盘的缓存文件。

从标准 InputStream> 读取时,可能需要将先前读取的信息保存在缓存中,因为底层流不允许重新读取数据。类似地,当写入标准 OutputStream 时,可以使用缓存来允许更改先前写入的值,然后再将其刷新到最终目的地。

缓存可以驻留在主内存或磁盘上。将此标志设置为 false 将禁止将磁盘用于未来的流,这在处理小图像时可能是有利的,因为创建和销毁文件的开销被消除了。

在启动时,该值设置为 true。

于 2012-04-19T20:02:07.333 回答
5

两次提及ImageIO.setUseCache(false)都是正确的。但是,如果您不喜欢全局禁用 ImageIO 的磁盘缓存,另一种方法是将流显式包装在 a 中MemoryCacheImageOutputStream(它执行内存缓存而不是磁盘缓存):

ByteArrayOutputStream baos = new ByteArrayOutputStream ();
ImageOutputStream stream = new MemoryCacheImageOutputStream(baos);
ImageIO.write(image, "png", stream);
stream.close();
return baos.toByteArray();
于 2013-12-13T16:18:37.877 回答
3

默认情况下,即使您只使用流,ImageIO 也会将其缓存写入磁盘。尝试使用以下方法禁用缓存:

ImageIO.setUseCache(false);
于 2012-04-19T20:02:30.640 回答
1

((DataBufferByte)img.getRaster().getDataBuffer()).getData()如果您的图像是字节格式,则自动返回一个字节数组。根本不需要任何 IO。

于 2012-12-14T23:33:46.573 回答