Java 没有无符号数(char
是 16 位无符号数,但它不是数字,并且数学char
总是会导致隐式转换为int
)
如果您将 2 个字节的无符号数据读入 ashort
并希望查看 0-65535(而不是 -32768 - 32767)范围内的值,则必须使用可以具有该范围内的值的类型。
在 16bit 的情况下,short
下一个更大的是 32bit int
。成功的转换是
short signed = ...;
int unsigned = signed & 0xFFFF;
假设signed
有这个值0xFFFF
会发生什么:
short signed = -1; // FFFF on byte level
表达式signed & 0xFFFF
包含 ashort
和 a int
。0xFFFF
是一个字面整数类型数,当在 Java 源代码中找到它时会被视为int
. 您可以long
通过将其更改为来实现0xFFFFL
(如果您想将 unsigned 转换为 ,则需要这样做int
)long
。
由于&
运算符需要双方都在一个通用类型中,Java 会默默地转换较小的类型。
int stillSigned = (int) signed; // hidden step
它仍将具有完全相同的值 -1,因为在查看它时它是无符号的,但它在 bytelevel 上更改为0xFFFFFFFF
.
现在应用位操作来删除所有添加FF
的 s
int unsigned = stillSigned & 0xFFFF;
你最终0x0000FFFF
会在字节级别上看到 65535 的值。
由于您碰巧有 16 位值,因此您可以使用char
并简单地将其转换为int
.
char value = ...;
int unsigned = value;
但上述方法适用于任何无符号转换:byteValue & 0xFF
, shortValue & 0xFFFF
,intValue & 0xFFFFFFFFL
接下来你应该做的是不要使用简单InputStream
的做
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
byte[] buffer = new byte[384];
in.read(buffer);
原因是InputStream#read(byte[])不能保证读取缓冲区中所需的所有字节。它返回它已读取的字节数或-1
流是否完成。手动编写代码来确保你有一个填充的缓冲区是讨厌的,但有一个简单的解决方案:DataInputStream
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
DataInputStream
具有非常好的功能,您可以使用:
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
int unsignedShort = in.readUnsignedShort();
从数据中获取不同数字的另一种方法byte[]
是使用ByteBuffer
,因为它提供了类似的方法.getShort()
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
while (byteBuffer.hasRemaining()) {
int unsigned = byteBuffer.getChar();
System.out.println(unsigned);
}