将4个字节转换为int


73

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

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

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

11111111 11111111 11111111 11111111

将为-1

01111111 11111111 11111111 11111111

将会 Integer.MAX_VALUE ( 2147483647 )

Answers:


72

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());

希望这可以帮助。



34

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

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

资料来源:这里


28

您应该将其放入这样的函数中:

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);

现在,您有了一个InputStream自动缓存1024个字节的,这要处理的麻烦少得多。这样,您可以一次愉快地读取4个字节,而不必担心过多的I / O。

其次,您还可以使用DataInputStream

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

甚至:

int i = in.readInt();

完全不用担心构造int


我只需要考虑以下事实:我的数组可能无法读取确切的% 4字节,对吗?
OscarRyz

如果数组的长度不是%4,则可以用0填充其余字节。(因为x | 0:= x和0 << n:= 0)。
达朱

3
您的代码存在一个主要问题-Java的字节类型为SIGNED,因此如果设置了任何字节的高位,则您的代码还将在结果int中设置所有高位。您需要屏蔽每个字节的高位,然后再进行移位和运算,例如(bytes[0] & 0xff) | ((bytes[1] & 0xff) << 8) | ...
克里斯·多德

1
我讨厌这样说,但是您的补偿支持已被完全破坏。请访问ideone.com/uCpovu,那里也有修复程序。
量子

1
感谢您的代码片段,我应该在这里指出一个错误-ret |= (int)bytes[i] & 0xFF;应该是ret |= (int)bytes[i + offset] & 0xFF;-否则,偏移参数将被完全忽略。
Ying

17

只是看看如何实现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));

8
应当注意的是,这是针对大端顺序字节的,其中对little的支持仅需进行很小的更改:return((ch4 << 24)+(ch3 << 16)+(ch2 << 8)+(ch1 << 0));
Paul Gregoire

这是不正确的。例如,如果第4个字节等于-1,其他则等于0,则结果为-1,但应为255。int k =((byte)-1)<< 0; System.err.println(k); // -1
Mikhail Ionkin '18

@MikhailIonkin您的评论错误,并且此代码正确。in.read()不返回字节。如果这样做,则将符号扩展存储在int变量中时会发生。但是in.read()返回转换为int而没有符号扩展名的流的下一个字节。因此,如果流的下一个字节为0xFF,则in.read()将返回0x000000FF。in.read()返回-1的唯一方法是到达流的末尾。
克雷格·帕顿

@CraigParton是的,但问题是如何转换4个字节,而不是4个整数
Mikhail Ionkin '18

5

最简单的方法是:

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

- 要么 -

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

1
假设他的二进制文件包含大端字节序的整数。否则会失败。太可怕了 :)
stmax 2010年

4

尝试这样的事情:

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

这是假定最低字节在前。如果最高字节在前,则可能必须交换索引(从0到3)。

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


尽管从概念上我同意Andrey的观点,但我希望任何后裔编译器都可以解决这个问题并为您解决。但是,<<为此更清晰。
Bill K 2010年

@Andrey:公平地说,Java编译器可能会自动转换x * 256x << 8
cletus

取决于编译器的质量:)
Andrey

这不是因为您应该使用“更快”的代码<<,而是因为可读性。通过使用<<,很明显,我们正在执行位运算而不是乘法。实际上,我什+至将|s更改为s
Justin

1
for (int i = 0; i < buffer.length; i++)
{
   a = (a << 8) | buffer[i];
   if (i % 3 == 0)
   {
      //a is ready
      a = 0;
   }       
}

1

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

new BigInteger(bytes).intValue();

或表示极性:

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

0

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

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

这是经过良好测试的功能


0

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

这段代码使用了最少的CPU时间,但是分配了一个ByteBuffer直到Java 10的JIT摆脱了分配。

int result;

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

此代码是不分配任何内容的性能最佳的代码。不幸的是,与上面的代码相比,它消耗了56%的CPU时间。

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] << 24) | ((array[i + 1] & 0xff) << 16) | ((array[i + 2] & 0xff) << 8) | (array[i + 3] & 0xff)即不转换为short第一个),则与ByteBuffer解决方案相比,其效果同样好。我想它可能会作为一种通用模式进行优化。
john16384 '19

0

将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) );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.