1

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

2 回答 2

1

ImageIO.read 将读取到输入流的末尾。这意味着没有数据可供读取,这就是为什么当您尝试从中读取更多数据时得到 null 的原因。

如果要重用输入流,则必须对其调用 reset() ;但这只有在底层 InputStream 实现支持重置时才有效,请参阅 InputStream 的 markSupported()。

这是简单但幼稚的解决方法。

请记住,您已经将图像读入内存,因此您实际上不需要这样做。这有点笨拙,但您可以将其写入 ByteArrayOutputStream,然后构建一个新的 ByteArrayInputStream。

如果我这样做,我可能会先将其读入字节数组。为此,请查看 Commons IOUtils.read()。然后我会根据需要构建一个新的 ByteArrayInputStream 和 reset() ,因为它肯定支持标记。

于 2012-11-14T22:36:29.470 回答
0

我想,您可以将原始输入流包装在BufferedInputStream中,并使用mark()保存流中的起始位置,并使用reset()返回它。

要完全回答您的问题:每个流都按顺序读取(通常有某种内部指针指向当前位置)。在第一个之后ImageIO.read(),将读取流直到其结束,因此,任何进一步的读取操作都不会返回任何数据(通常 -1 表示流的结束)。使用 mark() 您可以保存某个位置,然后使用 reset() 返回该位置。

于 2012-11-14T22:25:33.390 回答