Java :知道 ImageIO.read() (以及其他类似方法)读取了多少字节

Java : know how much bytes were read by ImageIO.read() (and maybe other similar methods)

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

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

Just in case, i made a small diagram

提前致谢

所有缓冲读取方法return实际读取的字节数。

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

Returns: the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached.

ImageInputStream can do what you want. It implements DataInput并且拥有InputStream的大部分方法。它有 getStreamPositionseekskipBytes 方法。

但是,正如您正确指出的那样,ImageIO.read(ImageInputStream) 会关闭流,阻止您阅读多张图片。

解决方案是避免使用 ImageIO.read,而是使用 ImageIO.getImageReaders. Then you can invoke an ImageReader’s read 方法显式获取 ImageReader,该方法不会关闭流。

以下是我的实现方式:

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));
    }));
}