14

我想知道这里记录的解决方案是否仍然是解决方案,或者有没有其他方法从 4 个字节中获取一个 int?

谢谢你。

编辑:我从套接字 .read 获取字节 []

编辑:int recvMsgSize = in.read(Data, 0, BufferSize);如果recvMsgSize 为-1,我知道连接已断开。

当我使用 DataInputStream 而不是 InputStream 时如何检测到这一点?

谢谢。

编辑:对于接受正确答案的悠悠球表示歉意。但是在 mihi 更新最终响应之后,该方法似乎是可靠的,并且减少了扩展编码,并且在我看来是最佳实践。

4

5 回答 5

20

您必须非常小心任何扩大转换和数字提升,但下面的代码将 4byte转换为int

    byte b1 = -1;
    byte b2 = -2;
    byte b3 = -3;
    byte b4 = -4;
    int i = ((0xFF & b1) << 24) | ((0xFF & b2) << 16) |
            ((0xFF & b3) << 8) | (0xFF & b4);
    System.out.println(Integer.toHexString(i)); // prints "fffefdfc"

也可以看看

  • Java代码将字节转换为十六进制
    • 注意掩盖的需要& 0xFF——如果你正在使用,你可能最终会做很多这样的事情,byte因为所有算术运算都会提升为int(或long
于 2010-05-15T13:16:49.620 回答
19

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

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

或者,如果您的类路径中有 Google 的guava-libraries,那么您可以使用以下快捷方式:

int result = Ints.fromByteArray(array);

Longs.fromByteArray这样做的好处是您可以为其他类型( 、Shorts.fromByteArray等)提供同样出色的 API 。

于 2010-05-15T13:51:12.630 回答
8

取决于您从哪里获得这 4 个字节:

http://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#readInt()

http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#getInt(int)

当然,您仍然可以手动执行此操作,但在大多数情况下,使用其中之一(如果您必须转换具有大量字节的字节数组,您可能希望使用 aDataInputStream周围的ByteArrayInputStream例如)更容易。

编辑:如果您需要更改字节序,则必须使用 ByteBuffer,或者自己反转字节,或者自己进行转换,因为 DataInput 不支持更改字节序。

Edit2:当您从套接字输入流中获取它们时,我会将其包装成 aDataInputStream并使用它来读取各种数据。特别是因为 InputStream.read(byte[]) 不能保证填充整个字节数组...... DataInputStream.readFully 会。

DataInputStream in = new DataInputStream(socket.getInputStream());
byte aByte = in.readByte();
int anInt = in.readInt();
int anotherInt = in.readInt();
short andAShort = in.readShort(); // 11 bytes read :-)
byte[] lotOfBytes = new byte[anInt];
in.readFully(lotOfBytes);

Edit3:当从流中多次读取时,它们将继续从您停止的位置读取,即 aByte 将是字节 0,anInt 将是字节 1 到 4,anInt 将是字节 5 到 8,等等。 readFully 将在所有这些之后继续读取并且会阻塞直到它读到lotOfbytes.

当流停止(连接断开)时,您将得到EOFException而不是 -1,因此如果得到 -1,则 int 确实是 -1。

如果您根本不想解析任何字节,则可以 skip() 它们。使用 DataInputStream 无法以两种不同的方式解析一个字节(即首先从字节 0 到 3 读取一个 int,然后从字节 2 到 5 读取一个),但通常也不需要。

例子:

// read messages (length + data) until the stream ends:
while (true) {
int messageLength;
try {
    messageLength = in.readInt(); // bytes 0 to 3
} catch (EOFException ex) {
    // connection dropped, so handle it, for example
    return;
}
byte[] message = new byte[messageLength];
in.readFully(message);
// do something with the message.
}
// all messages handled.

希望这能回答您的其他问题。

于 2010-05-15T13:09:26.937 回答
-1

功能风格的解决方案(只是为了多样化,恕我直言使用起来不太方便):

private int addByte (int base, byte appendix) {
    return (base << 4) + appendix;
}

public void test() {
    byte b1 = 5, b2 = 5, byte b3 = 0, b4 = 1;
    int result = addByte (addByte (addByte (addByte (0, b1), b2), b3), b4);
}
于 2010-05-15T13:34:04.583 回答
-3

正如 mihi 所说,这取决于您从哪里获取这些字节,但这段代码可能有用:

int myNumber = (((int)byteOne) << 0) |
    (((int)byteTwo) << 8) |
    (((int)byteThree) << 16) |
    (((int)byteFour) << 24);
于 2010-05-15T13:20:33.500 回答