Java 8 使用ByteArrayInputStream的危险/保证;“正确”;标记/重置行为

Java 8 使用ByteArrayInputStream的危险/保证;“正确”;标记/重置行为,java-8,fileinputstream,bufferedinputstream,bytearrayinputstream,Java 8,Fileinputstream,Bufferedinputstream,Bytearrayinputstream,这个问题可能是泛泛的,但我试图理解这里的主要含义 我正在尝试使用BCEL库进行字节码工程,部分工作流程要求我多次读取同一字节码文件(从一开始)。流程如下所示 // 1. Get Input Stream // 2. Do some work // 3. Finish // 4. Do some other work. 在第4步,我将需要重置标记或获取流,就好像它从一开始。我知道有以下几种选择 1) 使用BufferedInputStream包装流-获得“重置为无效标记”IOExcepti

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

我正在尝试使用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,因为我不知道调用最后一个
标记的位置,因此调用更高标记位置的
reset
将导致IOException。我更喜欢使用ByteArrayInputStream,因为它对我来说需要最少的代码更改,但是有人能建议选项2还是选项3更好吗

我知道,对于JDK中的
ByteArrayInputStream
BufferedInputStream
,mark()和reset()的实现是不同的


关于

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

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

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


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

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


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

因此,基本上您读取的是一个
文件
。类
文件?为什么不把它读一次,然后把它存储在一个字节数组中呢?@Eugene是的,先生,我已经在做了——它是有效的,但我是一个信徒或“专家意见”,希望有一个我可能没有考虑过的陷阱。你知道什么吗?我只知道当你不想读取整个输入流时,使用标记和重置是很重要的;或者你想读下几个字节,以便知道下一步该做什么;否则,将其读入数组是最简单的(对我来说也是最清楚的)@Eugene好的,这很有帮助。所以您是说,如果我想重新启动,那么为
ByteArrayInputStream
调用reset()应该正确地将其重置回流的位置0(我的意思是,开始)?i、 e.不应该有任何错误行为(因为我到目前为止还没有遇到任何问题)?well reset会将它(如果markSupported==true)重置为任何标记,而不是零,这可能是您的意思。但是,是的,如果这是支持的话,我会将文件内容(字节[])包装到
ByteArrayInputStream
中,并传递它-API中的最小更改-这对我来说很有用。看起来你和@Eugene都在你的评论中提到了这一点。我现在对此感到高兴。