【问题标题】:Convert 4 bytes to int将 4 个字节转换为 int
【发布时间】:2010-03-04 22:41:32
【问题描述】:

我正在读取这样的二进制文件:

InputStream in = new FileInputStream( file );
byte[] buffer = new byte[1024];
while( ( in.read(buffer ) > -1 ) {

   int a = // ??? 
}

我想要读取最多 4 个字节并从中创建一个 int 值,但是我不知道该怎么做。

我觉得我必须一次抓取 4 个字节,并执行一个“字节”操作(如 >> > & FF 和类似的东西)来创建新的 int

这个成语是什么?

编辑

哎呀,这结果有点复杂(解释一下)

我想要做的是,读取一个文件(可能是 ascii,二进制,没关系)并提取它可能具有的整数。

例如假设二进制内容(以 2 为底):

00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010

整数表示应该是 1 , 2 对吧? :- / 前 32 位为 1,其余 32 位为 2。

11111111 11111111 11111111 11111111

应该是 -1

01111111 11111111 11111111 11111111

应该是Integer.MAX_VALUE ( 2147483647 )

【问题讨论】:

    标签: java data-conversion


    【解决方案1】:

    ByteBuffer 具有此功能,并且能够处理小端和大端整数。

    考虑这个例子:

    // read the file into a byte array File file = new File("file.bin"); FileInputStream fis = new FileInputStream(file); byte [] arr = new byte[(int)file.length()]; fis.read(arr); // create a byte buffer and wrap the array ByteBuffer bb = ByteBuffer.wrap(arr); // if the file uses little endian as apposed to network // (big endian, Java's native) format, // then set the byte order of the ByteBuffer if(use_little_endian) bb.order(ByteOrder.LITTLE_ENDIAN); // read your integers using ByteBuffer's getInt(). // four bytes converted into an integer! System.out.println(bb.getInt());

    希望这会有所帮助。

    【讨论】:

    【解决方案2】:

    如果您已经将它们放在 byte[] 数组中,则可以使用:

    int result = ByteBuffer.wrap(bytes).getInt();
    

    来源:here

    【讨论】:

      【解决方案3】:

      你应该把它放到这样的函数中:

      public static int toInt(byte[] bytes, int offset) {
        int ret = 0;
        for (int i=0; i<4 && i+offset<bytes.length; i++) {
          ret <<= 8;
          ret |= (int)bytes[i] & 0xFF;
        }
        return ret;
      }
      

      例子:

      byte[] bytes = new byte[]{-2, -4, -8, -16};
      System.out.println(Integer.toBinaryString(toInt(bytes, 0)));
      

      输出:

      11111110111111001111100011110000
      

      这负责用完字节并正确处理负字节值。

      我不知道执行此操作的标准函数。

      需要考虑的问题:

      1. 字节序:不同的 CPU 架构将组成 int 的字节以不同的顺序排列。根据您如何提出字节数组开始,您可能不得不担心这一点;和

      2. 缓冲:如果您一次抓取 1024 个字节并在元素 1022 处开始一个序列,您将在获得 4 个字节之前到达缓冲区的末尾。最好使用某种形式的缓冲输入流来自动缓冲,这样您就可以重复使用readByte() 而不必担心;

      3. 尾随缓冲区:输入的结尾可能是奇数字节(具体不是 4 的倍数),具体取决于源。但是,如果您创建输入开头并且“保证”是 4 的倍数(或至少是一个前提条件),您可能不需要关心它。

      要进一步详细说明缓冲点,请考虑BufferedInputStream

      InputStream in = new BufferedInputStream(new FileInputStream(file), 1024);
      

      现在您有了一个 自动 一次缓冲 1024 个字节的 InputStream,处理起来不那么尴尬了。这样您就可以愉快地一次读取 4 个字节,而不必担心过多的 I/O。

      其次你也可以使用DataInputStream:

      InputStream in = new DataInputStream(new BufferedInputStream(
                           new FileInputStream(file), 1024));
      byte b = in.readByte();
      

      甚至:

      int i = in.readInt();
      

      根本不用担心构造ints。

      【讨论】:

      • 我只需要考虑我的数组可能无法准确读取 % 4 字节,对吧?
      • 如果数组的长度不是 %4,那么你可以用 0 填充剩余的字节。(因为 x | 0 := x 和 0
      • 您的代码有一个主要问题——java 的字节类型是有符号的,所以如果设置了任何字节的最高位,您的代码也会设置结果 int 中的所有高位。你需要在移位和oring之前屏蔽掉每个字节的高位,例如(bytes[0] &amp; 0xff) | ((bytes[1] &amp; 0xff) &lt;&lt; 8) | ...
      • 我不想这么说,但是您的偏移支持完全被破坏了。请参阅ideone.com/uCpovu,我也有修复。
      • 感谢代码 sn-p,我应该在这里指出一个错误 - ret |= (int)bytes[i] &amp; 0xFF; 应该真的是 ret |= (int)bytes[i + offset] &amp; 0xFF; - 否则偏移参数将被完全忽略。
      【解决方案4】:

      看看DataInputStream.readInt()是怎么实现的;

          int ch1 = in.read();
          int ch2 = in.read();
          int ch3 = in.read();
          int ch4 = in.read();
          if ((ch1 | ch2 | ch3 | ch4) < 0)
              throw new EOFException();
          return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
      

      【讨论】:

      • 需要注意的是,这是针对big-endian有序字节,而对little的支持只需要很小的改动:return ((ch4
      • 不正确。例如,如果第 4 个字节等于 -1,而其他字节为 0,则结​​果为 -1,但应为 255。 int k = ((byte)-1)
      • @MikhailIonkin 你的评论是错误的,这段代码是正确的。 in.read() 不返回一个字节。如果是这样,则在将其存储在 int 变量中时会发生符号扩展。但是 in.read() 返回转换为 int 的流的下一个字节,没有符号扩展。因此,如果流的下一个字节是 0xFF,in.read() 将返回 0x000000FF。 in.read() 返回 -1 的唯一方法是到达流的末尾。
      • @CraigParton 是的,但问题是如何转换 4 个字节,而不是 4 个整数
      【解决方案5】:

      最简单的方法是:

      RandomAccessFile in = new RandomAccessFile("filename", "r"); 
      int i = in.readInt();
      

      -- 或--

      DataInputStream in = new DataInputStream(new BufferedInputStream(
          new FileInputStream("filename"))); 
      int i = in.readInt();
      

      【讨论】:

      • 假设他的二进制文件包含大端签名的整数。否则它会失败。太可怕了。 :)
      【解决方案6】:

      试试这样的:

      a = buffer[3];
      a = a*256 + buffer[2];
      a = a*256 + buffer[1];
      a = a*256 + buffer[0];
      

      这是假设最低字节在前。如果最高字节首先出现,您可能必须交换索引(从 0 到 3)。

      基本上对于您要添加的每个字节,您首先将 a 乘以 256(等于向左移动 8 位),然后添加新字节。

      【讨论】:

      • 虽然我在概念上同意 Andrey,但我希望任何血统编译器都能解决这个问题并为您解决。但是,
      • @Andrey:公平地说,Java 编译器可能会自动将x * 256 翻译成x &lt;&lt; 8
      • 取决于编译器的质量 :)
      • 这不是因为您应该使用&lt;&lt; 的“更快”代码,而是因为可读性。通过使用&lt;&lt;,很明显我们是在进行位运算而不是乘法运算。事实上,我什至会将+s 更改为|s
      【解决方案7】:

      这是一个适合我的简单解决方案:

      int value = (a&255)+((b&255)<<8)+((c&255)<<16)+((d&255)<<24);
      

      a 是最低有效字节

      b 是第二个最低有效字节

      c 是第二个最重要的字节

      d 是最高字节

      【讨论】:

        【解决方案8】:
        for (int i = 0; i < buffer.length; i++)
        {
           a = (a << 8) | buffer[i];
           if (i % 3 == 0)
           {
              //a is ready
              a = 0;
           }       
        }
        

        【讨论】:

          【解决方案9】:

          您还可以将 BigInteger 用于可变长度字节。您可以根据需要将其转换为 Long、Integer 或 Short。

          new BigInteger(bytes).intValue();
          

          或表示极性:

          new BigInteger(1, bytes).intValue();
          

          【讨论】:

            【解决方案10】:

            为了将无符号的 4 字节读取为整数,我们应该使用 long 变量,因为符号位被视为无符号数的一部分。

            long result = (((bytes[0] << 8 & bytes[1]) << 8 & bytes[2]) << 8) & bytes[3]; 
            result = result & 0xFFFFFFFF;
            

            这是测试良好的功能

            【讨论】:

              【解决方案11】:

              以下代码在位置index 处从array(一个byte[])读取4 个字节并返回一个int。我尝试了 Java 10 上其他答案的大部分代码以及我梦想的其他一些变体。

              此代码使用最少的 CPU 时间,但分配 ByteBuffer 直到 Java 10 的 JIT 摆脱分配。

              int result;
              
              result = ByteBuffer.
                 wrap(array).
                 getInt(index);
              

              此代码是性能最好的代码,它不分配任何东西。不幸的是,与上述代码相比,它消耗的 CPU 时间增加了 56%。

              int result;
              short data0, data1, data2, data3;
              
              data0  = (short) (array[index++] & 0x00FF);
              data1  = (short) (array[index++] & 0x00FF);
              data2  = (short) (array[index++] & 0x00FF);
              data3  = (short) (array[index++] & 0x00FF);
              result = (data0 << 24) | (data1 << 16) | (data2 << 8) | data3;
              

              【讨论】:

              • 如果您这样做:(array[i] &lt;&lt; 24) | ((array[i + 1] &amp; 0xff) &lt;&lt; 16) | ((array[i + 2] &amp; 0xff) &lt;&lt; 8) | (array[i + 3] &amp; 0xff)(即首先不转换为short)与ByteBuffer 解决方案相比,它的性能同样出色。我想它可能会被优化为一种常见的模式。
              【解决方案12】:

              将 4 字节数组转换为整数:

              //Explictly declaring anInt=-4, byte-by-byte
              byte[] anInt = {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xfc}; // Equals -4
              //And now you have a 4-byte array with an integer equaling -4...
              //Converting back to integer from 4-bytes...
              result = (int) ( anInt[0]<<24 | ( (anInt[1]<<24)>>>8 ) | ( (anInt[2]<<24)>>>16) | ( (anInt[3]<<24)>>>24) );
              

              【讨论】:

                猜你喜欢
                • 2011-02-19
                • 2020-03-01
                • 2018-07-04
                • 2011-04-16
                • 2016-03-04
                • 2016-02-20
                • 1970-01-01
                相关资源
                最近更新 更多