Java 将BuffereImage转换为不带I/O的字节[]

Java 将BuffereImage转换为不带I/O的字节[],java,bufferedimage,javax.imageio,in-memory,Java,Bufferedimage,Javax.imageio,In Memory,您好,我在内存中有一个BuffereImage实例,出于性能考虑,我希望将其转换为byte[]以编码为base64字符串,而不进行I/O操作。我使用了以下API: ByteArrayOutputStream baos = new ByteArrayOutputStream (); ImageIO.write(image,"png",baos); return baos.toByteArray(); 但是,此API仍然隐式地将映像写入OS temp目录,如果基础OS temp目录已满且无法创建t

您好,我在内存中有一个BuffereImage实例,出于性能考虑,我希望将其转换为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的情况下进行转换?请告知。

通过以下方法禁用ImageIO缓存:

根据javadoc,默认为开启:

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

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

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

启动时,该值设置为true。


默认情况下,ImageIO将其缓存写入磁盘,即使您仅使用流。尝试使用以下命令禁用缓存:

ImageIO.setUseCache(false);

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

两次提到的
ImageIO.setUseCache(false)
都是正确的。但是,如果您不想全局禁用ImageIO的磁盘缓存,另一种方法是显式地将流包装在
MemoryCacheMageOutputStream
中(这样做是在内存中缓存而不是磁盘缓存):


我对这种情况感到惊讶。这几乎肯定是JVM中的一个bug。你试过最新版本吗?@彼得劳瑞:为什么你认为这是一个bug?有一整节课。然而,我在
ImageIO
中根本没有意识到这种机制。IMHO,磁盘缓存在填满驱动器之前不应该自动写入数据。上一次你的浏览器因为填满了你的驱动器而崩溃是什么时候。;)有没有一种不用ImageIO就可以做到这一点的方法?我有一个类似的问题,但我想使用一个替代方案,因为性能的原因,它不再是真的,至少在1.8
com.sun.imageio.spi.OutputStreamImageOutputStreamSpi#createOutputStreamInstance
不检查流的类型,但检查
useCache
参数。无论如何,如果有一种方法可以在本地禁用缓存,那就太好了。@sedovav上述解决方案确实提供了一种“本地”禁用磁盘缓存的方法。当您像那样直接创建MemoryCacheMageOutputStream时,您从未点击Spi,因此它所做的一切都是无关的。PS:请注意,ImageOutputSream不是OutputStream的子类,尽管它的名称是。还有一个单独的ImageIO.write重载。非常感谢你!
ImageIO.setUseCache(false);
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
ImageOutputStream stream = new MemoryCacheImageOutputStream(baos);
ImageIO.write(image, "png", stream);
stream.close();
return baos.toByteArray();