java - 读取包含无符号数字的二进制流

标签 java kotlin jvm binaryfiles java-io

我想读取包含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/

    相关文章:

    javascript - Java 类和 JavaScript 类之间的区别?

    android - 客户端上的 Bcrypt 哈希密码与服务器密码不匹配

    android - 如何在 Kotlin 中实现一个可以处理不同大小单元格的回收器 View ?

    java - 解释 Java *客户端* 安全问题和 *服务器* 安全问题之间的区别

    java - 实时服务器上的 MYSQL 未知列错误

    java - hibernate 多个 @OneToMany 关系在父关系中生成更多结果

    java - Apache Tomcat 启用 HTTP

    android - Activity 的 TextView 为空

    java - 如何理解 javap 输出中的 LocalVariableTable 区域

    Java进程在发送kill信号时不会终止