当前位置: 首页 > 知识库问答 >
问题:

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

楚皓君
2023-03-14

我看到一个奇怪的行为与ImageIO. read()方法。

我将InputStream传递给这个方法,当我第二次尝试读取它时,它无法读取并返回null。

我试图上传图像到亚马逊S3,我想创建3个版本的图像。原始和2缩略图。我的问题是,当我想创建2个缩略图时,我需要使用ImageIO. read()读取输入流。如果我运行这个方法2相同的InputStream我得到null为第二次读取。

我可以通过只读取一个并将相同的BuffereImage传递给scaling方法来避免这个问题。但是,我仍然需要我的方法获得的InputStream传递给其他版本的AmazonS3服务,以便上传原始文件。

所以我的问题是,在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个答案

公宜春
2023-03-14

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

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

冯翔
2023-03-14

图像。read将读取到输入流的末尾。这意味着没有数据可以读取,这就是为什么当您尝试从中读取更多数据时,会出现null。

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

这是一个简单但幼稚的解决办法。

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

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

 类似资料:
  • 我有以下代码来解析一个JSON文件: 要处理以下JSON文件: 如果我执行此代码,我将收到以下错误: 所以我开始一步一步地调试应用程序,看看part processing()中的哪个代码部分抛出了这个异常。令人惊讶的是,那里的所有代码都正常执行:没有抛出异常,也没有返回结果I except。 更让我惊讶的是,当我稍微改变第一种方法的代码时,它可以在不产生异常的情况下工作。 我不知道println方

  • null 结果将是0xFFFFFFFFFFFFFFFF0000(正确,寄存器溢出,但我们只更改2字节) 结果将为0x00000000000000000000(WTF?,寄存器溢出,但结果更改所有8个字节而不是4个字节。为什么是0x00000000000000,而不是0xFFFFFF00000000)

  • 接受这个基本输入 使用简单的字符串在组件中输入文本。很好,很好。双向数据绑定正在工作,您可以在按钮下方看到您输入的值。 现在,将组件中的输入_文本替换为 在你的模板中尝试以下方法: 您有4个输入,以及初始化(具有正确的名称)。但是当您尝试将文本放入字段时,您失去了焦点并且input_text数组保持不变({{input_text}}始终显示相同的数组) 将[(ngModel)]=“输入文本[i]”

  • 问题内容: 我在GregorianCalendar类中遇到一个奇怪的行为,我想知道我是否真的做得不好。 仅当初始化日期的月份的实际Maximum大于我将日历设置为的月份时,才追加此值。 这是示例代码: 我知道问题是由于日历初始化日期是31天(可能是5月),与设置为2月(28天)的月份混淆了。修复很容易(只需在设置年和月之前将day_of_month设置为1),但是我想知道这确实是想要的行为。有什么

  • 问题内容: 我正在为一个问题而苦苦挣扎,我不明白为什么它不起作用。如何通过将变量传递并转换为? 为什么在顶部代码段中不起作用,但在行下方的底部代码段中起作用? 唯一的区别似乎是添加了一个额外的变量,该变量也被键入为? 问题答案: 该是一种原始类型,同时是一个普通的Java类。您不能在原始类型上调用方法。但是该方法在上可用,如javadoc中所示 有关这些原始类型的更多信息,请参见此处

  • 问题内容: 为什么的到哪里去了? 问题答案: 删除任何字符,并从字符串的开头和结尾。