我有一个程序,我必须将BufferedImage序列化到磁盘然后再读回来。目前我正在使用原始图像格式
ImageIO.getImageReadersByFormatName("raw");
经过大量测试后,它的性能似乎在相同的数据上变化很大(从一秒钟到15秒不等)。
1.知道发生了什么事吗?
2.用于完成此任务的Java中最快的图像读取器/写入器是什么?
由于
答案 0 :(得分:2)
那就是说,我认为png
通常是一个很好的选择。
答案 1 :(得分:0)
除非您需要在特定程序之外进行互操作,否则通过ImageIO进行序列化可能是一个缓慢的解决方案。直接读取和写入BufferedImage的像素可能会更快。这是一个完整的解决方案:
public class SerializedImage
implements Serializable {
private BufferedImage mImage;
public SerializedImage( BufferedImage image ) {
mImage = image;
}
public BufferedImage getImage() {
return mImage;
}
private void writeObject( ObjectOutputStream streamOut )
throws IOException {
streamOut.writeInt( mImage.getWidth() );
streamOut.writeInt( mImage.getHeight() );
streamOut.writeInt( mImage.getType() );
streamOut.writeObject( ( (DataBufferInt) mImage.getRaster().getDataBuffer() ).getData() );
}
private void readObject( ObjectInputStream streamIn )
throws IOException, ClassNotFoundException {
mImage = new BufferedImage( streamIn.readInt(), streamIn.readInt(), streamIn.readInt() );
int[] savedBuffer = (int[]) streamIn.readObject();
int[] buffer = ( (DataBufferInt) mImage.getRaster().getDataBuffer() ).getData();
System.arraycopy( savedBuffer, 0, buffer, 0, savedBuffer.length );
}
}
更新: @haraldK要求一些基准。像所有的微观基准测试一样,你应该用一粒盐。正如@haraldK指出的那样,如果您将序列化表单写入磁盘,I / O可能会成为限制因素。始终测试您自己的用例。
但是,内存序列化/反序列化(到字节数组)的简单基准测试速度提高了10倍以上。鉴于a)PNG压缩是一项非平凡的任务,这似乎不合理。 b)可能PNG压缩必须至少读取像素数据,然后对其进行大量处理,而SerializedImage只需读取像素数据即可完成。 / p>
以下是代码:
// Create
BufferedImage image = new BufferedImage( 100, 200, BufferedImage.TYPE_INT_ARGB );
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setColor( Color.red );
graphics.fillRect( 1, 1, 50, 50 );
SerializedImage serializedImage = new SerializedImage( image );
long start = System.currentTimeMillis();
for( int loop = 0; loop < 10_000; loop++ ) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// Write
try ( ObjectOutputStream objectOutputStream = new ObjectOutputStream( outputStream ) ) {
objectOutputStream.writeObject( serializedImage );
}
// Read
try ( ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream( outputStream.toByteArray() ) ) ) {
( (SerializedImage) objectInputStream.readObject() ).getImage();
}
}
long end = System.currentTimeMillis() - start;
System.out.println( "SerializedImage took " + end + "ms" );
start = System.currentTimeMillis();
for( int loop = 0; loop < 10_000; loop++ ) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// Write
ImageIO.write( image, "png", outputStream );
// Read
ImageIO.read( new ByteArrayInputStream( outputStream.toByteArray() ));
}
end = System.currentTimeMillis() - start;
System.out.println( "ImageIO took " + end + "ms" );
出于好奇,我尝试使用FileOutputStream / FileInputStream。它仍然比ImageIO快,但速度只快了4倍。 @ haraldK的一些实验(下图)仅快了约2倍。所以你的里程可能会有所不同。