【问题标题】:Java : know how much bytes were read by ImageIO.read() (and maybe other similar methods)Java:知道 ImageIO.read() 读取了多少字节(可能还有其他类似的方法)
【发布时间】:2022-02-03 16:55:52
【问题描述】:

我正在制作一个从二进制流中读取数据的 java 程序(使用 DataInputStream)。

有时在这个过程中我需要读取一个数据块,但是读取它的方法(我无法修改)会在到达块的末尾之前停止(这是正常行为,显然它只是不需要最后一个字节,但我对它们在那里的事实无能为力)。这本身不是问题,因为我确切地知道块有多长,即我知道块中有多少字节,所以我可以跳过字节(使用skipBytes(int) 方法)直到块结束; 问题是:我实际上不知道该方法实际读取(或留下)多少字节,所以我不知道需要跳过多少字节才能到达块的末尾。
有什么办法吗:

  • 知道从某个时间点开始在流中读取了多少字节?
  • 知道从一个流中读取了多少字节吗?
  • 任何其他方式我都可以知道我的数据块读取方法刚刚读取了多少字节(因为它不会直接告诉我)?

Just in case, i made a small diagram

提前致谢

【问题讨论】:

  • 你是说流源总是发送 N 个字节,即使图像数据可能只占其中的一小部分?
  • 是的,或多或少。它是一个包含图像的二进制文件,在每个图像之前我都有图像的长度;但是应该是图像的块的最后一个字节只是......无用的字节,我不知道它们为什么在那里,但是图像读取功能不会读取它们,我需要跳过它们才能恢复阅读有用的数据
  • 您可以将 ImageInputStream 传递给 ImageIO.read。 ImageInputStream 除了大多数标准的 InputStream 方法和 DataInput 方法外,还有一个getStreamPosition() 方法。只需确保通过它而不是底层 InputStream 进行所有读取,因为混合读取两者会导致奇怪的行为。
  • 嗯,这看起来确实是我需要的。我很想实际上只是用 ImageInputStream 替换我的 DataInputSteam,因为它也有 DataInput 方法,但由于 ImageInputStream 只是一个接口,我真的不知道确切使用哪个类。我会试着调查一下。
  • 这就是为什么我链接到一个创建 ImageInputStream 的方法。你不需要关心它是一个接口。重要的是,您将拥有一个 ImageIO 内部类型的对象,它实现了 ImageInputStream。

标签: java io inputstream datainputstream


【解决方案1】:

ImageInputStream 可以为所欲为。它实现了DataInput,并且拥有InputStream的大部分方法。它有getStreamPositionseekskipBytes 方法。

但是,正如您正确指出的那样,ImageIO.read(ImageInputStream) 会关闭流,从而阻止您读取多个图像。

解决方案是避免使用 ImageIO.read,而是使用 ImageIO.getImageReaders 显式获取 ImageReader。然后您可以调用 ImageReader 的 read 方法,该方法不会关闭流。

我是这样实现的:

public void readImages(InputStream source,
                       Consumer<? super BufferedImage> imageHandler)
throws IOException {
    // Every image is at a byte index which is a multiple of this number.
    int boundary = 5000;

    try (ImageInputStream stream = ImageIO.createImageInputStream(source)) {
        while (true) {
            long pos = stream.getStreamPosition();

            Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
            if (!readers.hasNext()) {
                break;
            }

            ImageReader reader = readers.next();
            reader.setInput(stream);
            BufferedImage image = reader.read(0);

            imageHandler.accept(image);

            pos = stream.getStreamPosition();
            long bytesToSkip = boundary - (pos % boundary);
            if (bytesToSkip < boundary) {
                stream.skipBytes(bytesToSkip);
            }
        }
    }
}

我是这样测试的:

try (InputStream source = new BufferedInputStream(
        Files.newInputStream(Path.of(filename)))) {

    reader.readImages(source, img -> EventQueue.invokeLater(() -> {
        JOptionPane.showMessageDialog(null, new ImageIcon(img));
    }));
}

【讨论】:

    【解决方案2】:

    所有缓冲读取方法都返回实际读取的字节数。

    引用documentation for InputStream#read(byte[] b):

    返回: 读入缓冲区的总字节数,如果由于已到达流的末尾而没有更多数据,则为 -1。

    【讨论】:

    • 这里的读取方法不是InputStream#read()。是ImageIO#read(Input stream),不返回读取的字节数
    猜你喜欢
    • 2012-07-28
    • 1970-01-01
    • 2012-10-07
    • 2010-12-22
    • 1970-01-01
    • 2018-01-04
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多