1

这个问题可能是通用的,但我试图理解这里的主要含义。

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

// 1. Get Input Stream

// 2. Do some work

// 3. Finish

// 4. Do some other work.

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

BufferedInputStream1) 使用- 获得“重置为无效标记”IOException 的机会来包装流

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

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

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

我知道mark() 和reset() 的实现在JDKByteArrayInputStreamBufferedInputStreamJDK 中是不同的。

问候

4

1 回答 1

3

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

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

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


最好的解决方案是将整个类文件读入一个数组一次并直接使用该数组,例如用于您控制的代码或当您对库有选择时(例如,ASMClassReader支持使用字节数组而不是InputStream) .

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

如果您必须处理无法缓冲全部内容的非常大的文件,则再次调用getInputStream()将是一种选择,但是,对于类文件则不是这种情况。

于 2017-11-20T11:57:56.683 回答