google 的从 c# 到 java 的协议缓冲区 - 协议消息标签的线路类型无效

Posted

技术标签:

【中文标题】google 的从 c# 到 java 的协议缓冲区 - 协议消息标签的线路类型无效【英文标题】:google's protocol buffer from c# to java - Protocol message tag had invalid wire type 【发布时间】:2012-12-24 10:17:51 【问题描述】:

我正在 C# 中创建一个流并尝试在 java 中读取它,但我收到错误消息:“协议消息标记的线路类型无效。”当我在我的 java 代码中读取它时,在 c# 中创建的对象。

详情: 我从一个相等的 .proto 文件(见下文)开始创建对应的 .java 文件和 .cs 文件(使用版本“protobuf-2.4.1”中的 java 协议和 protobuf-csharp-port-2.4.1.473 进行编译-c# 的完整二进制文件)。 我成功创建了 addressbook.java 和 addressbook.cs。

对象是在 c# 中创建的,并使用以下 c# 代码写入文件:

[...]
byte[] bytes;

        //Create a builder to start building a message
        Person.Builder newContact = Person.CreateBuilder();

        //Set the primitive properties
        newContact.SetId(1)
                  .SetName("Foo")
                  .SetEmail("foo@bar");

        //Now add an item to a list (repeating) field
        newContact.AddPhone(
            //Create the child message inline
            Person.Types.PhoneNumber.CreateBuilder().SetNumber("555-1212").Build()
            );

        //Now build the final message:
        Person person = newContact.Build();


        newContact = null;
        using(MemoryStream stream = new MemoryStream())
        
            //Save the person to a stream
            person.WriteTo(stream);
            bytes = stream.ToArray();


            //save this to a file (by me)
            ByteArrayToFile("personStreamFromC#", bytes);
[...]

我将创建的文件“personStreamFromC#”复制到我的 java 解决方案并尝试使用以下 java 代码读取它:

 AddressBook.Builder addressBook = AddressBook.newBuilder();

// Read the existing address book.
try 
    FileInputStream input = new FileInputStream(args[0]);
    byte[] data = IOUtils.toByteArray(input);
    addressBook.mergeFrom(data);
  // Read the existing address book.
  AddressBook addressBookToReadFrom =
          AddressBook.parseFrom(new FileInputStream(args[0]));
  Print(addressBookToReadFrom);

但我收到以下消息:

线程“main”com.google.protobuf.InvalidProtocolBufferException 中的异常:协议消息 标签的电线类型无效。在 com.google.protobuf.InvalidProtocolBufferException.invalidWireType(InvalidProtocolBufferException.java:78) 在 com.google.protobuf.UnknownFieldSet$Builder.mergeFieldFrom(UnknownFieldSet.java:498) 在 com.google.protobuf.GeneratedMessage$Builder.parseUnknownField(GeneratedMessage.java:438) 在 com.example.tutorial.AddressBookProtos$Person$Builder.mergeFrom(AddressBookProtos.java:1034) 在 com.example.tutorial.AddressBookProtos$Person$Builder.mergeFrom(AddressBookProtos.java:1) 在 com.google.protobuf.CodedInputStream.readMessage(CodedInputStream.java:275) 在 com.example.tutorial.AddressBookProtos$AddressBook$Builder.mergeFrom(AddressBookProtos.java:1715) 在 com.example.tutorial.AddressBookProtos$AddressBook$Builder.mergeFrom(AddressBookProtos.java:1) 在 com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:300) 在 com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:238) 在 com.google.protobuf.AbstractMessageLite$Builder.mergeFrom(AbstractMessageLite.java:162) 在 com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:716) 在 com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:238) 在 com.google.protobuf.AbstractMessageLite$Builder.mergeFrom(AbstractMessageLite.java:153) 在 com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:709) 在 AddPerson.main(test.java:104)

.proto 文件下方: 包教程; 消息人 所需的字符串名称 = 1; 必需的 int32 id = 2; // 此人的唯一 ID 号。 可选字符串 email = 3;

 enum PhoneType 
   MOBILE = 0;
   HOME = 1;
   WORK = 2;
 

 message PhoneNumber 
   required string number = 1;
  optional PhoneType type = 2 [default = HOME];
 

 repeated PhoneNumber phone = 4;
 

message AddressBook 
  repeated Person person = 1;
  

有什么想法吗??

【问题讨论】:

您在 C# 中将 Person 对象写入文件,然后在 Java 中读取 AddressBook,我认为这是不正确的。试试Person.parseFrom(new FileInputStream(args[0])); 哇!你说的对 !!!非常感谢,它解决了问题! @hoaz 您应该将其添加为答案 【参考方案1】:

您在 C# 中将 Person 对象写入文件,然后在 Java 中读取 AddressBook,我认为这是不正确的。尝试在您的 Java 代码中执行以下操作:

Person.parseFrom(new FileInputStream(args[0]));

【讨论】:

【参考方案2】:

一个可能导致无效线型错误(尤其是在使用文件时)的常见错误是:覆盖现有文件而不截断它。我们看不到您的 ByteArrayToFile,但坦率地说,File.WriteAllBytes 可能是一个更简单的选择。问题在于,如果新数据小于原始内容,任何剩余的额外字节本质上都是垃圾

我的建议:

检查是否可以在c#中反序列化;如果不能,则错误肯定在文件处理中 如果它在 c# 中工作,请检查您是如何将文件获取到 java 代码的:您是否将其复制到任何地方? 并检查您是否在所有阶段都使用二进制(而非文本)处理

【讨论】:

1) 使用 File.WriteAllBytes 没有帮助,Java 中仍然出现同样的异常 2) c# 中的反序列化工作完美 - 见下文: 3) 我使用简单的复制粘贴复制文件C# 中的 bin 目录到 Java 中的 bin .. 我应该做不同的吗? @MarcGravell 这对解决类似问题有很大帮助!谢谢你的建议!

以上是关于google 的从 c# 到 java 的协议缓冲区 - 协议消息标签的线路类型无效的主要内容,如果未能解决你的问题,请参考以下文章

使用协议缓冲区将二进制文件从 Java 服务器发送到 C# Unity3d 客户端

C++ 中的 Google 协议缓冲区:从现有结构创建消息

在 Windows 中使用 MinGW 的 Google 协议缓冲区

Google 协议缓冲区交叉编译

.Net 协议缓冲区到 JSON,JsonFormatReader 类不处理最外面的花括号?

Google 协议缓冲区和 stl 向量、映射和提升共享指针