我看到了ImageIO.read()方法的奇怪行为。
我将InputStream传递给此方法,当我第二次尝试读取它时,它无法读取并返回null。
我正在尝试将图像上传到Amazon S3,我想创建3个版本的图像。原始和2缩略图。我的问题是,当我想创建2个缩略图时,我需要使用ImageIO.read()读取InputStream。如果我为同一个InputStream运行此方法2,我将获得第二次读取的null。
我可以通过只读取一个并将相同的BufferedImage传递给缩放方法来避免这个问题。但是我仍然需要我的方法传递给其他AmazonS3服务的InputStream来上传原始文件。
所以我的问题是,在ImageIO第一次读取输入流后,有没有人知道输入流会发生什么?
下面的代码示例
public String uploadImage(InputStream stream, String filePath, String fileName, String fileExtension) {
try {
String originalKey = filePath + fileName + "." + fileExtension;
String smallThumbKey = filePath + fileName + ImageConst.Path.SMALL_THUMB + "." + fileExtension;
String largetThumbKey = filePath + fileName + ImageConst.Path.LARGE_THUMB + "." + fileExtension;
BufferedImage image = ImageIO.read(stream);
InputStream smallThumb = createSmallThumb(image, fileExtension);
InputStream largeThumb = createLargeThumb(image, fileExtension);
uploadFileToS3(originalKey, stream);
uploadFileToS3(smallThumbKey, smallThumb);
uploadFileToS3(largetThumbKey, largeThumb);
return originalKey;
} catch (IOException ex) {
Logger.getLogger(ManageUser.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
答案 0 :(得分:1)
ImageIO.read将读取到输入流的末尾。这意味着没有数据可供阅读,这就是为什么当你尝试从中读取更多数据时你会得到null。
如果要重用输入流,则必须在其上调用reset();但这只有在底层InputStream实现支持重置时才有效,请参阅InputStream的markSupported()。
这是简单但天真的修复。
请记住,您已经将图像读入内存,因此您根本不需要这样做。这有点笨拙,但您可以将其写入ByteArrayOutputStream,然后构建一个新的ByteArrayInputStream。
如果我这样做,我可能会把它读成一个字节数组开头。查看Commons IOUtils.read()。然后我根据需要构建一个新的ByteArrayInputStream和reset(),因为它肯定支持标记。
答案 1 :(得分:0)
我想,您可以将原始输入流包装在BufferedInputStream中,然后使用mark()保存流中的起始位置,并reset()返回它。
完全回答你的问题:每个流都按顺序读取(通常有某种内部指针指向当前位置)。在第一个ImageIO.read()
之后,读取流直到其结束,因此,任何进一步的读取操作都不会返回任何数据(通常为-1以指示流的结束)。使用mark()可以保存某个位置,然后使用reset()返回它。