Dangers/Guarantees 用于使用 ByteArrayInputStream 具有 "Correct" mark/reset 行为

Dangers/Guarantees for using ByteArrayInputStream to have "Correct" mark/reset behaviour

这个问题可能很笼统,但我试图理解这里的主要含义。

我正在尝试使用 BCEL 库进行一些字节码工程,部分工作流程要求我多次读取相同的字节码文件(从头开始)。流程如下

// 1. Get Input Stream

// 2. Do some work

// 3. Finish

// 4. Do some other work.

在第 4 步,我将需要重置标记或像从头开始一样获取流。我知道以下选择。

1) 使用 BufferedInputStream 包装流 - 有机会获得 "Resetting to invalid mark" IOException

2) 使用 ByteArrayInputStream 包装它 - 它始终有效,即使一些在线研究表明它是错误的?

3) 如果我需要再次从流中读取,只需调用 getInputStream()

我正在尝试了解哪个选项更适合我。我不想使用 BufferedInputStream 因为我不知道最后一个 mark 在哪里被调用,所以为更高的标记位置调用 reset 会导致 IOException。我更喜欢使用 ByteArrayInputStream,因为它需要对我进行最少的代码更改,但是有人可以建议选项#2 还是选项#3 会更好吗?

我知道 JDK 中 ByteArrayInputStreamBufferedInputStream 的 mark() 和 reset() 实现不同。

此致

mark/reset的问题不仅在于你必须提前知道这些调用之间读取的最大数据量,你还必须知道你的代码是否'重新委派给将在内部使用该功能,使您的标记过时。使用 mark/reset 的代码不可能为调用者记住和恢复之前的标记。

因此,虽然可以通过将总文件大小指定为最大值 readlimit 来解决最大问题,但在将 InputStream 传递给任意库时,您永远不能依赖工作标记未明确记录的函数永远不会在内部使用 mark/reset 功能。

此外,BufferedInputStream 得到与总文件大小匹配的 readlimit 不会比 ByteArrayInputStream 包装一个包含整个文件的数组更有效,因为两者最终都会维护相同大小的缓冲区。


最好的解决方案是将整个class文件读入数组一次,然后直接使用该数组,例如对于您控制下的代码或当您可以选择有关库时(例如,ASM 的 ClassReader 支持使用字节数组而不是 InputStream)。

如果您必须将 InputStream 提供给坚持使用它的库函数,例如 BCEL,则在需要时将字节数组包装到 ByteArrayInputStream 中,但 创建一个new ByteArrayInputStream 每次你必须重新解析 class 文件。构建新的 ByteArrayInputStream 不需要任何成本,因为它是一个轻量级的包装器并且是可靠的,因为它不以任何方式依赖于旧输入流的状态。您甚至可以让多个 ByteArrayInputStream 实例同时读取同一个数组。

再次调用 getInputStream() 是一个选项,如果你必须处理非常大的文件,而缓冲整个内容不是一个选项,但是,class 不是这种情况文件。