当前位置: 首页 > 知识库问答 >
问题:

如何使用字节缓冲区序列化字节数组开始遵循大端格式?

公孙新觉
2023-03-14

我需要使用Java代码将字节数组值写入Cassandra。然后我将有我的C程序,它将从Cassandra检索字节数组数据,然后将其反序列化。

我将要写入Cassandra的字节数组由三个字节数组组成,如下所述-

short employeeId = 32767;
long lastModifiedDate = "1379811105109L";
byte[] attributeValue = os.toByteArray();

现在,我将编写employeeIdlastModifiedDateattributeValue一起组成一个单字节数组,我将结果字节数组写入Cassandra,然后我将使用我的C程序从Cassandra检索字节数组数据,然后反序列化以提取employeeIdlastModifiedDate和它的attributeValue

我不确定在写Cassandra时是否应该在Java代码中使用Big-Endian,以便在读回C代码时简化它?

我在Java方面做了一次尝试,确保它在将所有内容写入单字节数组时都遵循特定的格式(Big-Endian),然后这个字节数组也将被写回Cassandra,但不确定这是否正确?

public static void main(String[] args) throws Exception {

    String os = "Byte Array Test";
    byte[] attributeValue = os.getBytes();

    long lastModifiedDate = 1379811105109L;
    short employeeId = 32767;

    ByteArrayOutputStream byteOsTest = new ByteArrayOutputStream();
    DataOutputStream outTest = new DataOutputStream(byteOsTest);

    // merging everything into one Byte Array here
    outTest.writeShort(employeeId);
    outTest.writeLong(lastModifiedDate);
    outTest.writeInt(attributeValue.length);
    outTest.write(attributeValue);

    byte[] allWrittenBytesTest = byteOsTest.toByteArray();

    // initially I was writing allWrittenBytesTest into Cassandra...

    ByteBuffer bb = ByteBuffer.wrap(allWrittenBytesTest).order(ByteOrder.BIG_ENDIAN);

    // now what value I should write into Cassandra?
    // or does this even looks right?

    // And now how to deserialize it?

}

有人能帮我处理这件事吗?谢谢

我可能会错过关于字节缓冲区的详细信息,因为这是我第一次使用它...

  1. 首先,我应该在我的用例中使用ByteByffer吗?
  2. 其次,如果是,那么在我的用例中使用它的最佳方式是什么...?

我要确保的唯一一件事是,我通过遵循Big-Endians字节顺序格式正确地写入Cassandra,这样在C端,我在反序列化该字节数组时不会遇到任何问题。。。


共有3个答案

卞坚成
2023-03-14

因为字节数组终结根本没有意义。因此,如果卡桑德拉不尝试解释你的数据,你可以使用是否大/小端。所以编码只对多字节值有意义。

如果您要将数据用于不同的客户端,并且可能在不同的平台上,我建议您采取一些协议(例如使用BIG端),并在所有客户端上使用相同的端。例如,java客户端代码看起来像这样:

ByteBuffer bb = ByteBuffer.allocate(attributeValue.length + 14).order(ByteOrder.BIG_ENDIAN);
    bb.putShort(employeeId);
    bb.putLong(lastModifiedDate);
    bb.putInt(attributeValue.length);
    bb.put(attributeValue);

如果要使用需要的API,则必须使用ByteBuffer。例如,NIO通道与ByteBuffers一起工作,因此,如果要使用SocketChannel进行连接,则可以使用ByteBuffer。还可以使用ByteBuffer来正确格式化多字节值。例如,对于上面的代码,您可以从缓冲区获取字节数组,并通过一个套接字发送,其中3个第一个字段使用大端符号打包:

sendByteArray(bb.array());
...
柴嘉年
2023-03-14

首先,我从来没有使用过cassandra,我只回答关于ByteBuffer的部分。

在发送字节之前,您应该先将所有内容放入字节缓冲区,否则您无法控制所存储内容的深度,这正是使用字节缓冲区的目的。

要发送字节,请使用:

int size = 2 + 8 + 4 + attributeValue.length; // short is 2 bytes, long 8 and int 4

ByteBuffer bbuf = ByteBuffer.allocate(size); 
bbuf.order(ByteOrder.BIG_ENDIAN);

bbuf.putShort(employeeId);
bbuf.putLong(lastModifiedDate);
bbuf.putInt(attributeValue.length);
bbuf.put(attributeValue);

bbuf.rewind();

// this is a bad approach because if you modify the returned array
// you are directly modifying the ByteBuffer's internal array.
byte[] bytesToStore = bbuf.array();

// best approach is copy the internal buffer
byte[] bytesToStore = new byte[size];
bbuf.get(bytesToStore);

现在,您可以通过Testostore存储,并将它们发送给cassandra。

重读:

byte[] allWrittenBytesTest = magicFunctionToAcquireDataFromCassandra();

ByteBuffer bb = ByteBuffer.wrap(allWrittenBytesTest);
bb.order(ByteOrder.BIG_ENDIAN);
bb.rewind();

int size = allWrittenBytesTest.length - 14;
short employeeId = bb.getShort();
long lastModifiedDate = bb.getLong();
int attributeValueLen = bb.getInt();
byte[] attributeValue = new byte[size];
bb.get(attributeValue); // read attributeValue from the remaining buffer

您甚至不需要存储attributeValue长度,因为可以通过从AllWrittenByTester中减去14来再次确定长度。长度(14是其他字段大小[2 4 8]之和)。

编辑代码时,我有一些打字错误。

何飞翰
2023-03-14

使用Cassandra的本机CQL驱动程序,而不是手动序列化ByteBuffers for Thrift:http://github.com/datastax/java-driver

 类似资料:
  • 问题内容: 有没有一种方法可以使用BufferedReader读取ByteBuffer而不必先将其转换为String?我想读取相当大的ByteBuffer作为文本行,并且出于性能方面的考虑,我想避免将其写入磁盘。在ByteBuffer上调用toString不起作用,因为生成的String太大(它抛出java.lang.OutOfMemoryError:Java堆空间)。我本来以为API中会有一些东

  • Javascript ArrayBuffer或TypedArrays没有任何类型的appendByte()、appendBytes()或appendBuffer()方法。所以,如果我想一次填充一个数组缓冲一个值,我该怎么做呢?

  • 我目前正在处理一些小的endian二进制数据,我已经到了一个尴尬的地步,需要将奇数字节转换成整数值。 现在使用类,我能够很好地使用函数读取int和long,它们分别读取4和8个字节。 然而,在本例中,我需要读取三个字节,并将它们转换为int。我尝试过使用(2字节1字节),但我认为这不是正确的方法。 我猜我需要对字节进行位移位才能得到正确的int值,但我总是对位移位感到困惑。 此外,我还以为字节缓冲

  • 问题内容: 我必须在Java中以字节数组形式存储一些常量值(UUID),并且我想知道初始化这些静态数组的最佳方法是什么。这就是我目前的做法,但我觉得必须有更好的方法。 有什么我可以使用的,虽然效率可能较低,但看起来会更干净?例如: 问题答案: 使用将十六进制字符串转换为的函数,您可以执行 我建议您在使用Java将十六进制转储的字符串表示形式转换为字节数组中使用 DaveL定义的功能吗? 我将其插入

  • 我必须在java中以字节数组的形式存储一些常量值(UUID),我想知道初始化这些静态数组的最佳方法是什么。我现在就是这样做的,但我觉得一定有更好的办法。 有没有什么东西我可以使用,可能效率较低,但会看起来更干净?例如:

  • 问题内容: 方案:各种文件的大小以字节为单位存储在数据库中。将大小信息格式化为千字节,兆字节和千兆字节的最佳方法是什么?例如,我有一个MP3,Ubuntu显示为“ 5.2 MB(5445632字节)”。如何在网页上将其显示为“ 5.2 MB”,并且文件大小小于1 MB的文件显示为KB,文件大小大于1 GB的文件显示为GB? 问题答案: (取自php.net,那里还有许多其他示例,但我最喜欢这个示例