使用协议缓冲区序列化/反序列化独立整数

3

到目前为止,我一直在使用Protocol Buffers来使用代码生成的类序列化和反序列化对象。

现在我正在尝试序列化和反序列化一个单独的64位整数。问题是,在Java和C#中,我得到了不同的结果。

以下是我在Java中的操作方式...

private static byte[] convertLongToByteArray(long value) throws IOException {
    int size = CodedOutputStream.computeInt64SizeNoTag(value);
    byte[] buffer = new byte[size];
    CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer);
    codedOutputStream.writeInt64NoTag(value);
    codedOutputStream.flush();
    codedOutputStream.checkNoSpaceLeft();
    return buffer;
}

以下是我如何使用protobuf.net在C#中完成这个任务的代码:

public void SerializeLongValue()
{
    long n = 9876;
    byte[] memoryBuffer = null;
    using (MemoryStream destination = new MemoryStream())
    {
        ProtoBuf.Serializer.Serialize(destination, n);
        destination.Flush();
        memoryBuffer = destination.ToArray();
    }

    using (MemoryStream source = new MemoryStream(memoryBuffer))
    {
        long result = ProtoBuf.Serializer.Deserialize<long>(source);
        Assert.AreEqual(n, result);
    }
}

Java代码将数字9876转换为[0x94, 0x4D]

C#代码将数字9876转换为[0x08, 0x94, 0x4D]

如何使com.google.protobufprotobuf.net的输出完全相同?


1
注意:在protobuf-net中有一个名为ProtoWriter的类,它的工作方式有点类似于CodedOutputStream;但是,我怀疑它在写入最终可能是不完整/无效文档时可能会出现问题。在某种程度上,它看起来像是你想要的一种类似于ProtoReader.DirectReadVarintInt32的东西,但是a:写(而不是读),b:64位。目前还不存在一个在ProtoWriter实例之外的DirectWriteVarintInt64方法。 - Marc Gravell
@MarcGravell - 你的怀疑是正确的。如果线路类型未正确设置,ProtoWriter.WriteInt64会抛出异常,而且只有通过调用ProtoWriter.WriteFieldHeader才能设置线路类型。 - Andrew Shepherd
1个回答

2

protobuf.net的ProtoBuf.Serializer.Serialize方法会将一个字段头(字段号=1)强制写入流中。这是执行序列化的唯一方式;该方法调用了许多不公开的内部方法。

我使用的解决方案是修改Java代码以包含一个字段头。

以下是我新的Java代码。

private static byte[] convertLongToByteArray(long value) throws IOException {
    int size = CodedOutputStream.computeTagSize(1) + CodedOutputStream.computeInt64SizeNoTag(value);
    byte[] buffer = new byte[size];
    CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer);
    codedOutputStream.writeInt64(1, value);
    codedOutputStream.flush();
    codedOutputStream.checkNoSpaceLeft();
    return buffer;
}

public static long convertByteArrayToLong(byte[] byteArray) throws IOException {
    CodedInputStream codedInputStream = CodedInputStream.newInstance(byteArray);
    codedInputStream.readTag();
    return codedInputStream.readInt64();
}

我所做的更改如下:
  • 在计算所需缓冲区大小时,包括标签大小。
  • 不再使用CodedOutputStream.WriteInt64NoTag,而是调用CodedOutputStream.WriteInt64
  • 在读取回来时,在调用CodedOutputStream.ReadInt64之前调用CodedOutputStream.ReadTag

很好知道,谢谢分享。我正在考虑使用protobuf与一个我无法控制的Java程序进行通信。 - jdphenix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接