图像IO奇怪的行为重置输入流

时间:2012-11-14 22:16:25

标签: java image io bufferedimage

我看到了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;
}

2 个答案:

答案 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()返回它。