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 中 ByteArrayInputStream
和 BufferedInputStream
的 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 不是这种情况文件。
这个问题可能很笼统,但我试图理解这里的主要含义。
我正在尝试使用 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 中 ByteArrayInputStream
和 BufferedInputStream
的 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 不是这种情况文件。