Java中ByteArrayOutputStream写入后ByteArrayInputStream读取大长整型值异常问题
问题分析
读取代码的核心错误在于:readUInt16()返回的是有符号int类型,当读取的16位值超过0x7FFF(即最高位为1)时,该int值会成为负数,转成long时会触发符号扩展(高48位填充1),最终在readUInt64()的位运算中破坏高位数据,导致大值读取错误。
由于无法修改读取代码,只能通过调整写入逻辑来适配读取代码的缺陷。
修复方案
思路
限制写入的每个16位块的最高位为0(取值范围0~0x7FFF),避免readUInt16()返回负数。若原始值的16位块最高位为1,则将该位的进位传递到高位块,确保读取时不会触发符号扩展。
修复后的写入代码
ByteArrayOutputStream baos; public void writeUInt64(Long val) { long temp = val; // 拆分每个16位部分,确保最高位为0并处理进位 int v0 = (int) (temp & 0x7FFF); temp >>= 16; if ((val & 0x8000) != 0) { temp += 1; } int v1 = (int) (temp & 0x7FFF); temp >>= 16; if ((temp & 0x8000) != 0) { temp += 1; } int v2 = (int) (temp & 0x7FFF); temp >>= 16; if ((temp & 0x8000) != 0) { temp += 1; } int v3 = (int) (temp & 0x7FFF); writeUInt16(v0); writeUInt16(v1); writeUInt16(v2); writeUInt16(v3); } public void writeUInt16(int num) { baos.write(num >> 0); baos.write(num >> 8); }
说明
- 适用范围:此方案仅支持
val ≤ 0x7FFF7FFF7FFF7FFFL(约1.8×10¹⁹)的数值,超过该范围的UInt64值无法通过此方法正确读取。 - 根本解决:若需支持任意UInt64值,必须修改读取代码,将每个
readUInt16()的结果转为无符号16位值后再参与运算:public long readUInt64() throws IOException { return (readUInt16() & 0xFFFFL) | ((readUInt16() & 0xFFFFL) << 16L) | ((readUInt16() & 0xFFFFL) << 32L) | ((readUInt16() & 0xFFFFL) << 48L); }
内容的提问来源于stack exchange,提问作者user20240747
相关产品推荐
相关产品推荐

