如何连接 Crystal 中的字节
How to concatenate bytes in Crystal
我正在测试字节或切片的序列化,只是学习和尝试。我想在一个 10 字节的字段中绑定 3 个参数,但我现在不知道如何在 Crystal 中连接它们,也不知道是否可行。我知道我可以通过创建数组或元组来实现这一点,但我想尝试是否可以将参数混合到一个缓冲区中。
例如,我想要一个混合了 3 个参数的自描述二进制记录 ID:
类型 (UInt8) |类别 (UInt8) |微秒 (UInt64) = 总计 80 位 - 10 字节
type = 1_u8 # 1 byte
categ = 4_u8 # 1 byte
usec = 1527987703211000_u64 # 8 bytes (Epoch)
如何将所有这些变量连接到一个连续的 10 字节缓冲区中?
我想通过索引检索数据,如:
type = buff[0,1]
categ = buff[1,1]
usec = buff[2,8].to_u64 # (Actually not possible)
typ = 1_u8 # 1 byte
categ = 4_u8 # 1 byte
usec = 1527987703211000_u64 # 8 bytes (Epoch)
FORMAT = IO::ByteFormat::LittleEndian
io = IO::Memory.new(10) # Specifying the capacity is optional
io.write_bytes(typ, FORMAT) # Specifying the format is optional
io.write_bytes(categ, FORMAT)
io.write_bytes(usec, FORMAT)
buf = io.to_slice
puts buf
# --------
io2 = IO::Memory.new(buf)
typ2 = io2.read_bytes(UInt8, FORMAT)
categ2 = io2.read_bytes(UInt8, FORMAT)
usec2 = io2.read_bytes(UInt64, FORMAT)
pp typ2, categ2, usec2
Bytes[1, 4, 248, 99, 69, 92, 178, 109, 5, 0]
typ2 # => 1_u8
categ2 # => 4_u8
usec2 # => 1527987703211000_u64
这显示了一个为您的用例量身定制的示例,但 IO::Memory
通常应该用于 "concatenating bytes" -- 只需写入即可。
这不是您问题的答案,但当我尝试连接实际的 Bytes[]
时,我总是在这里结束。 Oleh 的回答仍然适用,但我尝试在此处提供更通用的方法:
# some bytes a
a = Bytes[131, 4, 254, 47]
# some other bytes b
b = Bytes[97, 98, 99]
# new buffer of sizes a and b
c = IO::Memory.new a.bytesize + b.bytesize
# without knowing the size of the slice, we just write byte by byte
a.each do |v|
# each byte can be represented by an u8
c.write_bytes UInt8.new v
end
# same for b
b.each do |v|
c.write_bytes UInt8.new v
end
# here you have your new bytes slice
c = c.to_slice
# => Bytes[131, 4, 254, 47, 97, 98, 99]
注意,这仅适用于默认的 IO::ByteFormat::LittleEndian
,因此在示例中省略了
我正在测试字节或切片的序列化,只是学习和尝试。我想在一个 10 字节的字段中绑定 3 个参数,但我现在不知道如何在 Crystal 中连接它们,也不知道是否可行。我知道我可以通过创建数组或元组来实现这一点,但我想尝试是否可以将参数混合到一个缓冲区中。
例如,我想要一个混合了 3 个参数的自描述二进制记录 ID:
类型 (UInt8) |类别 (UInt8) |微秒 (UInt64) = 总计 80 位 - 10 字节
type = 1_u8 # 1 byte
categ = 4_u8 # 1 byte
usec = 1527987703211000_u64 # 8 bytes (Epoch)
如何将所有这些变量连接到一个连续的 10 字节缓冲区中?
我想通过索引检索数据,如:
type = buff[0,1]
categ = buff[1,1]
usec = buff[2,8].to_u64 # (Actually not possible)
typ = 1_u8 # 1 byte
categ = 4_u8 # 1 byte
usec = 1527987703211000_u64 # 8 bytes (Epoch)
FORMAT = IO::ByteFormat::LittleEndian
io = IO::Memory.new(10) # Specifying the capacity is optional
io.write_bytes(typ, FORMAT) # Specifying the format is optional
io.write_bytes(categ, FORMAT)
io.write_bytes(usec, FORMAT)
buf = io.to_slice
puts buf
# --------
io2 = IO::Memory.new(buf)
typ2 = io2.read_bytes(UInt8, FORMAT)
categ2 = io2.read_bytes(UInt8, FORMAT)
usec2 = io2.read_bytes(UInt64, FORMAT)
pp typ2, categ2, usec2
Bytes[1, 4, 248, 99, 69, 92, 178, 109, 5, 0]
typ2 # => 1_u8
categ2 # => 4_u8
usec2 # => 1527987703211000_u64
这显示了一个为您的用例量身定制的示例,但 IO::Memory
通常应该用于 "concatenating bytes" -- 只需写入即可。
这不是您问题的答案,但当我尝试连接实际的 Bytes[]
时,我总是在这里结束。 Oleh 的回答仍然适用,但我尝试在此处提供更通用的方法:
# some bytes a
a = Bytes[131, 4, 254, 47]
# some other bytes b
b = Bytes[97, 98, 99]
# new buffer of sizes a and b
c = IO::Memory.new a.bytesize + b.bytesize
# without knowing the size of the slice, we just write byte by byte
a.each do |v|
# each byte can be represented by an u8
c.write_bytes UInt8.new v
end
# same for b
b.each do |v|
c.write_bytes UInt8.new v
end
# here you have your new bytes slice
c = c.to_slice
# => Bytes[131, 4, 254, 47, 97, 98, 99]
注意,这仅适用于默认的 IO::ByteFormat::LittleEndian
,因此在示例中省略了