我想读取包含32位无符号整数和8位无符号整数的二进制文件。我已经知道DataInputStream
了,但是它的方法readInt
返回有符号整数,没有读取无符号int的方法(对于16位和8位整数有这种方法)。
读取单独的字节并按位将它们串联是“正式”的方法吗?将字节读入ByteArray
并使用bitshift和按位or
从字节组成整数会大大降低性能吗?
最佳答案
您可以使用
long value = Integer.toUnsignedLong(dataInputStream.readInt());
这等效于Java 8之前的代码long value = dataInputStream.readInt() & 0xFFFFFFFFL;
关键是带符号或无符号只是位模式的不同解释,但是要读取四个字节的数量,readInt()
总是足够的。上面的操作将转换为带符号的long
,这是一种能够覆盖所有unsigned int值的数据类型。但是,由于
int
已经保存了所有信息,因此无需立即将其转换为long
。用来表示带符号数字的Two’s Complement甚至允许执行基本操作,即+
,-
和*
,而无需区分带符号的数字和无符号的数字。对于其他操作,Java 8引入了通过将int
值解释为无符号来执行它们的方法:Integer.divideUnsigned(…)
Integer.remainderUnsigned(…)
Integer.compareUnsigned(…)
Integer.toUnsignedString(…)
我遇到的一个实际例子是解析类文件。这些文件在某些地方的大小被编码为unsigned int,但是对于大多数标准Java API,类文件以字节数组或
ByteBuffer
实例的形式提供,它们不能包含超过23个字节。因此,处理一些大数字是不必要的复杂操作,因为它们无论如何还是无法纠正的,因为必须截断包含这么大规格的类文件。因此,处理此问题的代码基本上如下所示:
int size = input.readInt();
if(Integer.compareUnsigned(size, Integer.MAX_VALUE)>0) throw new IllegalArgumentException(
"truncated class file (attribute size "+Integer.toUnsignedString(size)+')');
// just use the int value
或没有Java 8功能(甚至更简单,只要读者理解Two’s Complement):
int size = input.readInt();
if(size < 0) throw new IllegalArgumentException(
"truncated class file (attribute size "+(size&0xFFFFFFFFL)+')');
// just use the int value
(另请参阅this answer)
关于java - 读取包含无符号数字的二进制流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63138575/