使用ByteArrayInputStream进行"纠正"的危险/保证标记/重置行为

时间:2017-11-20 11:18:46

标签: java-8 fileinputstream bufferedinputstream bytearrayinputstream

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

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

// 1. Get Input Stream

// 2. Do some work

// 3. Finish

// 4. Do some other work.

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

1)使用BufferedInputStream包裹流 - 有可能获得"重置为无效标记" IOException的

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

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

我想知道哪个选项对我更​​好。我不想使用BufferedInputStream,因为我不知道调用最后一个mark的位置,因此调用reset以获得更高的标记位置将导致IOException。我更喜欢使用ByteArrayInputStream,因为它需要我最小的代码更改,但是有人可以建议选项#2或选项#3会更好吗?

我知道JDK中{(1}}和ByteArrayInputStream的mark()和reset()实现是不同的。

此致

1 个答案:

答案 0 :(得分:3)

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

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

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

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

如果你必须将InputStream提供给坚持它的库函数,比如BCEL,那么在需要时将字节数组包装到ByteArrayInputStream,但创建一个新的 ByteArrayInputStream。构造新的ByteArrayInputStream不需要任何费用,因为它是一个轻量级的包装器并且是可靠的,因为它不依赖于任何方式的旧输入流的状态。您甚至可以让多个ByteArrayInputStream实例同时读取同一个数组。

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