如何通过使用 ByteBuffer 查看标头偏移量来制作字节数组?

Posted

技术标签:

【中文标题】如何通过使用 ByteBuffer 查看标头偏移量来制作字节数组?【英文标题】:How to make a byte arrary by looking at the header offsets using ByteBuffer? 【发布时间】:2014-10-21 00:56:32 【问题描述】:

我需要按照以下标头偏移格式为我的标头创建一个字节数组。

// below is the header offsets

// m_off_addressed_center must be the first byte
static constexpr uint32_t  m_off_addressed_center           = 0;
static constexpr uint32_t  m_off_record_version             = m_off_addressed_center + 1;
static constexpr uint32_t  m_off_num_records                = m_off_record_version + 1;
static constexpr uint32_t  m_off_buffer_used                = m_off_num_records + sizeof(uint32_t);
static constexpr uint32_t  m_off_address                    = m_off_buffer_used + sizeof(uint32_t);
static constexpr uint32_t  m_off_address_from               = m_off_address + sizeof(CustomerAddress);
static constexpr uint32_t  m_off_records_partition          = m_off_address_from + sizeof(CustomerAddress);
static constexpr uint32_t  m_off_already_replicated         = m_off_records_partition + 1;

// this is the full size of the header
static constexpr uint32_t m_head_offset = m_off_already_replicated + 1;

CustomerAddressuint64_t 的typedef,它是这样组成的-

typedef uint64_t   CustomerAddress;

void client_data(uint8_t datacenter, 
                  uint16_t client_id, 
                  uint8_t data_id, 
                  uint32_t data_counter,
                  CustomerAddress& customer_address)

    customer_address = (uint64_t(datacenter) << 56)
                    + (uint64_t(client_id) << 40)
                    + (uint64_t(data_id) << 32)
                    + data_counter;

以下是我开始的内容,我不确定我是否做对了所有事情?

ByteBuffer b = ByteBuffer.allocate(256 * 256); // allocating 64k buffer
b.order(ByteOrder.BIG_ENDIAN);

// header layout
int m_off_addressed_center = 1;
int m_off_record_version = 2;
int m_off_num_records = 1;
int m_off_buffer_used = 100;

long m_off_address = client_data((byte) 10, (short) 12, (byte) 30, 200);
long m_off_address_from = client_data((byte) 20, (short) 22, (byte) 40, 150);

int m_off_records_partition = 10;
int m_off_already_replicated = 20;

b.putInt(m_off_addressed_center);
b.putInt(m_off_record_version);
b.putInt(m_off_num_records);
b.putInt(m_off_buffer_used);

b.putLong(m_off_address);
b.putLong(m_off_address_from);  

b.putInt(m_off_records_partition);
b.putInt(m_off_already_replicated);

byte[] result = b.array();
System.out.println(result); 

下面是我的方法client_data

private static long client_data(byte datacenter, short client_id, byte data_id, int data_counter) 
    return ((long) (datacenter) << 56) | ((long) client_id << 40) | ((long) data_id << 32) | ((long) data_counter);

根据上面定义的标题偏移量,我是否得到了正确的结果?

【问题讨论】:

【参考方案1】:

你很接近。您的 records_partitionalready_replicated 值使用 int 而应该使用 byte

private static long client_data(byte datacenter, short client_id, byte data_id, int data_counter)

    return (((long) datacenter) << 56) |
           (((long) client_id) << 40) |
           (((long) data_id) << 32) |
            ((long) data_counter);

ByteBuffer b = ByteBuffer.allocate(28);
b.order(ByteOrder.BIG_ENDIAN);

// header layout
byte addressed_center = 1;
byte record_version = 2;
int num_records = 1;
int buffer_used = 100;
long address = client_data((byte) 10, (short) 12, (byte) 30, (in) 200);
long address_from = client_data((byte) 20, (short) 22, (byte) 40, (int) 150);
byte records_partition = 10;
byte already_replicated = 20;

b.put(     addressed_center);
b.put(     record_version);
b.putInt(  num_records);
b.putInt(  buffer_used);
b.putLong( address);
b.putLong( address_from);
b.put(     records_partition);
b.put(     already_replicated);

byte[] result = b.array();
System.out.println(result); 

或者:

private final static int m_off_addressed_center           = 0;
private final static int m_off_record_version             = m_off_addressed_center + 1;
private final static int m_off_num_records                = m_off_record_version + 1;
private final static int m_off_buffer_used                = m_off_num_records + 4;
private final static int m_off_address                    = m_off_buffer_used + 4;
private final static int m_off_address_from               = m_off_address + 8;
private final static int m_off_records_partition          = m_off_address_from + 8;
private final static int m_off_already_replicated         = m_off_records_partition + 1;

private final static int m_head_offset = m_off_already_replicated + 1;

ByteBuffer b = ByteBuffer.allocate(m_head_offset);
b.order(ByteOrder.BIG_ENDIAN);

// header layout
byte addressed_center = 1;
byte record_version = 2;
int num_records = 1;
int buffer_used = 100;
long address = client_data((byte) 10, (short) 12, (byte) 30, (in) 200);
long address_from = client_data((byte) 20, (short) 22, (byte) 40, (int) 150);
byte records_partition = 10;
byte already_replicated = 20;

b.put(     m_off_addressed_center,   addressed_center);
b.put(     m_off_record_version,     record_version);
b.putInt(  m_off_num_records,        num_records);
b.putInt(  m_off_buffer_used,        buffer_used);
b.putLong( m_off_address,            address);
b.putLong( m_off_address_from,       address_from);
b.put(     m_off_records_partition,  records_partition);
b.put(     m_off_already_replicated, already_replicated);

byte[] result = b.array();
System.out.println(result); 

【讨论】:

非常感谢雷米。我试过你的建议。一旦我使用您提供给我的 client_data 方法,它就会给我编译错误 - The method client_data(byte, short, byte, int) in the type ByteTest is not applicable for the arguments (int, int, int, int) 知道有什么问题吗? 我希望 Java 足够聪明,允许将数字文字传递给参数,并且它会找出要使用的正确数据类型。我猜不会。我更新了我的示例以使用类型转换。 感谢编辑。你能解释一下你提供的两种解决方案有什么区别吗?对我来说看起来一样,只是第二个在 put 方法中有两个参数。 阅读documentation,它告诉你有什么区别。

以上是关于如何通过使用 ByteBuffer 查看标头偏移量来制作字节数组?的主要内容,如果未能解决你的问题,请参考以下文章

multiboot2 标头在 ELF 文件中“为时已晚”(偏移量很大),即使它是第一部分

如何通过 UTC 偏移量确定时区?

PostgREST 在子查询或 CTE 中使用限制和偏移量

如何获取已删除分区中inode的块设备中的偏移量

.NET 通过时区名称获取时区偏移量

如何查看kafka消费者信息