Java 具有位大小定义的自定义序列化和反序列化
Java Custom Serialization and Deserialization with Bit size definitions
问题:
我需要从具有固定数据包格式定义的电子设备实现网络输入 reader。它有页眉、页脚和数据主体。数据包中的字段以位为单位定义。
示例:
字段 sequence_number 变量是编号为 8 到 31 的位,ack_status 是位 32。如何创建自定义序列化函数以便我可以将 java 对象与字节相互转换[] 从数据包中读取?
在 32 位数据包中
StartOfPacketHeader 4 位
CommandCode 4位
序列号23位
AckStatus 1bit
如何使用 byte[] 构造函数和 toBytes() 方法为此对象制作 Java 包装器 class。
使用可序列化接口无法控制单个数据大小。数据大小可能是奇数值,如 3 位或 18 位变量。我无法根据位指定变量的长度。
到目前为止我做了什么:
源实际上发送无符号整数,这意味着Java int 类型无法处理其整个范围。我需要定义所有数据类型来处理所有情况。我已经使用 BitSet class 执行 byte[] 到 Long 的转换,但它太乏味和令人困惑,因为 bitset 默认将位顺序反转为 Little Endian。
总结:
如何以最有效的方式将我从网络读取的 bytes[] 转换为我的对象,反之亦然,并为每个字段自定义定义?
您为此使用 DataInputStream
和 DataOutputStream
,为了提高效率,在它们下面分别使用 BufferedInputStream
或 BufferedOutputStream
。您必须自己编写位字段,但是这些 类 提供了网络字节顺序中的所有 Java 原语。
对于您发布的数据包,您需要这样的东西:
class Packet
{
private byte header;
private byte commandCode;
private int sequenceNumber;
private boolean ackStatus;
void write(DataOutput out) throws IOException
{
int wirePacket = header|(commandCode << 4)|(sequenceNumber << 8);
if (ackStatus)
{
wirePacket |= 0x80000000;
}
out.writeInt(wirePacket);
}
static Packet read(DataInput in) throws IOException
{
Packet packet = new Packet();
int wirePacket = in.readInt();
packet.header = (byte)(wirePacket & 0x0f);
packet.commandCode = (byte)((wirePacket >>> 4) & 0x0f);
packet.sequenceNumber = (wirePacket >>> 8) & 0x7FFFFF;
packet.ackStatus = (wirePacket & 0x80000000) != 0;
return packet;
}
// getters and setters. The setters must ensure that the values don't go out of range.
}
问题: 我需要从具有固定数据包格式定义的电子设备实现网络输入 reader。它有页眉、页脚和数据主体。数据包中的字段以位为单位定义。
示例: 字段 sequence_number 变量是编号为 8 到 31 的位,ack_status 是位 32。如何创建自定义序列化函数以便我可以将 java 对象与字节相互转换[] 从数据包中读取?
在 32 位数据包中
StartOfPacketHeader 4 位
CommandCode 4位
序列号23位
AckStatus 1bit
如何使用 byte[] 构造函数和 toBytes() 方法为此对象制作 Java 包装器 class。
使用可序列化接口无法控制单个数据大小。数据大小可能是奇数值,如 3 位或 18 位变量。我无法根据位指定变量的长度。
到目前为止我做了什么:
源实际上发送无符号整数,这意味着Java int 类型无法处理其整个范围。我需要定义所有数据类型来处理所有情况。我已经使用 BitSet class 执行 byte[] 到 Long 的转换,但它太乏味和令人困惑,因为 bitset 默认将位顺序反转为 Little Endian。
总结:
如何以最有效的方式将我从网络读取的 bytes[] 转换为我的对象,反之亦然,并为每个字段自定义定义?
您为此使用 DataInputStream
和 DataOutputStream
,为了提高效率,在它们下面分别使用 BufferedInputStream
或 BufferedOutputStream
。您必须自己编写位字段,但是这些 类 提供了网络字节顺序中的所有 Java 原语。
对于您发布的数据包,您需要这样的东西:
class Packet
{
private byte header;
private byte commandCode;
private int sequenceNumber;
private boolean ackStatus;
void write(DataOutput out) throws IOException
{
int wirePacket = header|(commandCode << 4)|(sequenceNumber << 8);
if (ackStatus)
{
wirePacket |= 0x80000000;
}
out.writeInt(wirePacket);
}
static Packet read(DataInput in) throws IOException
{
Packet packet = new Packet();
int wirePacket = in.readInt();
packet.header = (byte)(wirePacket & 0x0f);
packet.commandCode = (byte)((wirePacket >>> 4) & 0x0f);
packet.sequenceNumber = (wirePacket >>> 8) & 0x7FFFFF;
packet.ackStatus = (wirePacket & 0x80000000) != 0;
return packet;
}
// getters and setters. The setters must ensure that the values don't go out of range.
}