简体   繁体   English

如何使用Protocol-buffer在Java中反序列化文件?

[英]How to de-serialize the file in Java by using Protocol-buffer?

Want to create a serialized file in C# and then want to de-serialize the same in Java. 想要在C#中创建一个序列化文件,然后想在Java中对其进行反序列化。 For this , i am using Protocol buffer library. 为此,我使用协议缓冲库。 Here want i have done: 这里想要我做了:

In C#, I added protobuf-net.dll and the class which is to be serialized is represented as: 在C#中,我添加了protobuf-net.dll,要序列化的类表示为:

Person.cs Person.cs

 [ProtoBuf.ProtoContract]
 public class Person
 {
    [ProtoBuf.ProtoMember(1)]
    public int Id {get;set;}
    [ProtoBuf.ProtoMember(2)]
    public string Name { get; set; }
 }

and in the main method, serialized it like this: 并在main方法中,将其序列化为:

 var person = new Person
    {
        Id = 12345,
        Name = "Fred",
    };
  using (var file = File.Create("somepath\\person.bin"))
    {
        Serializer.Serialize(file, person);
    }

This bin file i copied and pulled in the ecilpse filesystem- android /sdcard and tried to de-serialize it 我在ecilpse filesystem- android / sdcard中复制并提取了这个bin文件,并尝试对其进行反序列化

In eclipse -JAVA, 在eclipse -JAVA中,

Added protobuf.jar, external library and created person.proto file which contains: 添加了protobuf.jar,外部库和创建的person.proto文件,其中包含:

message Person{
required int32 Id=1;
required string Name=2;
}

Can anyone please suggest how to de-serialize the object which was created in the C#? 任何人都可以建议如何反序列化在C#中创建的对象?

What does the Java documentation say about deserializing an object serialized by the Java version? Java文档对于反序列化由Java版本序列化的对象有何看法? Basically: "do that". 基本上:“做那个”。 There is no difference in the serialized data. 序列化数据没有区别。

If the problem is that the Java examples start with a .proto file, then use: 如果问题是Java示例以.proto文件开头,那么使用:

string proto = Serializer.GetProto<Person>();

Although the .proto you show looks fine. 虽然你展示的.proto看起来很好。

Create an InputStream to the file created in C#, and call 为C#中创建的文件创建一个InputStream ,然后调用

Person.parseFrom(InputStream)

There are other overloads to this method if you'd rather deal with bytes from that file. 如果您更愿意处理该文件中的字节,则此方法还有其他重载。

If you are implementing a protocol you'll need to include a header to identify what type of data the bytes represent. 如果要实现协议,则需要包含标头以标识字节所代表的数据类型。 From there you'd just select the correct proto to parse the data with. 从那里你只需选择正确的proto来解析数据。

EDIT 编辑

Here's a class I created for mapping id's to class's and vice versa to assist in developing a protocol with protobufs. 这是我创建的用于将id映射到类的类,反之亦然,以帮助开发具有protobufs的协议。 If you aren't developing a protocol for network transmission this might not help, but I'm pretty sure you are. 如果你没有开发网络传输协议,这可能没什么用,但我很确定你是。

I know you didn't ask for this, but perhaps you'll find it useful. 我知道你没有要求这个,但也许你会觉得它很有用。

Register ids to all your protobuff generators, then retrieve the correct generator for unserializing bytes on receive. 将id注册到所有protobuff生成器,然后检索正确的生成器,以便在接收时反序列化字节。 Get the correct ID for each protobuf object before you send. 在发送之前获取每个protobuf对象的正确ID。 ID would be included in every packet so you know what type of data is in each packet. ID将包含在每个数据包中,以便您知道每个数据包中的数据类型。 (Packet being abstract here, this would work with a stream protocol too.) (数据包在这里是抽象的,这也适用于流协议。)

public class MessageTypeMap {
private final Object lock;
final HashMap<Integer, GeneratedMessageLite> messageParserMap;
final HashMap<Class<?>, Integer> messageClassParserMap;

public MessageTypeMap() {
    this.messageParserMap = new HashMap<Integer, GeneratedMessageLite>();
    this.messageClassParserMap = new HashMap<Class<?>, Integer>();
    this.lock = new Object();
}

public void addMessageType(int typeID, GeneratedMessageLite message) {
    synchronized (this.lock) {
        this.messageParserMap.put(typeID, message);
        this.messageClassParserMap.put(message.getDefaultInstanceForType()
                .getClass(), typeID);
    }
}

public GeneratedMessageLite getBuilderFor(int id) throws ProtocolException {
    synchronized (this.lock) {
        if (this.messageParserMap.containsKey(id)) {
            GeneratedMessageLite lite = this.messageParserMap.get(id);
            return lite;
        } else {
            throw new ProtocolException("No message builder for ID " + id);
        }
    }
}

public int getIDFor(Object obj) throws ProtocolException {
    synchronized (this.lock) {
        if (obj == null) {
            throw new NullPointerException(
                    "Object null while retrieving type id.");
        }
        Class<?> c = obj.getClass();
        if (this.messageClassParserMap.containsKey(c)) {
            int typeID = this.messageClassParserMap.get(c);
            return typeID;
        } else {
            throw new ProtocolException("No type id for class "
                    + c.getSimpleName());
        }
    }
}

} }

Usage: 用法:

MessageTypeMap map = new MessageTypeMap();
//register the person type.
map.addMessageType(100, Person.getDefaultInstance());
//use this to unserialize whatever object some bytes are.
GeneratedMessageLite builder = mpa.getBuilderFor(100);
//be sure to include the type id with each transmission of an object.
int id = map.getIDFor(Person.getDefaultInstance());

The usual way how Protocol Buffers work is: Protocol Buffers的常用方法是:

  • You define your protocol in a small .proto text file. 您可以在一个小的.proto文本文件中定义协议。
  • You run the protobuf compiler on that file 您在该文件上运行protobuf编译器
  • proto compiler generates source code in all the languages you need to serialize & parse objects. proto编译器生成您需要序列化和解析对象所需的所有语言的源代码。

The library you use in C# is special. 您在C#中使用的库是特殊的。 It does not need that .proto file to start with. 它不需要.proto文件开头。 Instead you can create the protocol within your code by annotating classes (or whatever the terminology in C# is). 相反,您可以通过注释类(或C#中的任何术语)在代码中创建协议。

In order to use your in-code-generated protocol from Java you need the .proto file since Java does not support that type of definition in code. 为了使用Java中的代码生成协议,您需要.proto文件,因为Java不支持代码中的那种类型的定义。

You can either write the .proto file by hand or let the C# library generate it (see Marc Gravell's answer) - I would suggest you generate the file so you can't make mistakes in the definition. 您可以手动编写.proto文件或让C#库生成它(请参阅Marc Gravell的回答) - 我建议您生成文件,这样您就不会在定义中出错。

Once you have that file you run the protobuf compiler ( protoc ) (dowload) on the .proto file and it will generate a .java file for you. 获得该文件后,在.proto文件上运行protobuf编译器( protoc(dowload) ,它将为您生成.java文件。 That file has the Person class and everything required to serialize and parse. 该文件具有Person类以及序列化和解析所需的所有内容。

Now you include both protobuf[version].jar and the generated .java file in your project. 现在,您在项目中包含protobuf[version].jar和生成的.java文件。 The .proto file itself is not required in the project. 项目中不需要.proto文件本身。

Once you have done that simply use the generated code to parse the file: 完成后,只需使用生成的代码解析文件:

Person person = Person.parseFrom(new FileInputStream(file));

The only line of code that you write is that one above. 您编写的唯一代码行是上面的代码。

More details about the Java integration is found in the official tutorial 有关Java集成的更多详细信息,请参阅官方教程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM