这个问题可能是通用的,但我试图理解这里的主要含义。
我正在尝试使用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()实现是不同的。
此致
答案 0 :(得分:3)
mark
/ reset
的问题不仅在于您必须提前知道这些调用之间读取的最大数据量,您还必须知道您委派的代码是否是将在内部使用该功能,使您的标记过时。使用mark
/ reset
的代码无法记住并恢复调用者的先前标记。
因此,虽然可以通过将总文件大小指定为最大readlimit
来解决最大问题,但在将InputStream
传递给任意库函数时,您永远不能依赖工作标记没有明确记录从不在内部使用mark
/ reset
功能。
此外,BufferedInputStream
获得与readlimit
匹配的总文件大小不会比包含保存整个文件的数组的ByteArrayInputStream
更有效,因为它们最终都会维护缓冲区大小相同。
最好的解决方案是将整个类文件读入一个数组并直接使用该数组,例如:对于您可控制的代码或您对库的选择(例如,ASM的ClassReader
支持使用字节数组而不是InputStream
)。
如果你必须将InputStream
提供给坚持它的库函数,比如BCEL,那么在需要时将字节数组包装到ByteArrayInputStream
,但创建一个新的 ByteArrayInputStream
。构造新的ByteArrayInputStream
不需要任何费用,因为它是一个轻量级的包装器并且是可靠的,因为它不依赖于任何方式的旧输入流的状态。您甚至可以让多个ByteArrayInputStream
实例同时读取同一个数组。
再次调用getInputStream()
是一个选项,如果你必须处理非常大的文件,缓冲整个内容不是一个选项,但是,这不是类文件的情况。