想要在C#中创建一个序列化文件,然后想在Java中对其进行反序列化。为此,我使用协议缓冲库。这里想要我做完了:
在C#中,我添加了protobuf-net.dll,要序列化的类表示为:
Person.cs
[ProtoBuf.ProtoContract]
public class Person
{
[ProtoBuf.ProtoMember(1)]
public int Id {get;set;}
[ProtoBuf.ProtoMember(2)]
public string Name { get; set; }
}
并在main方法中,将其序列化为:
var person = new Person
{
Id = 12345,
Name = "Fred",
};
using (var file = File.Create("somepath\\person.bin"))
{
Serializer.Serialize(file, person);
}
我在ecilpse filesystem- android / sdcard中复制并提取了这个bin文件并尝试对其进行反序列化
在eclipse -JAVA中,
添加了protobuf.jar,外部库和创建的person.proto文件,其中包含:
message Person{
required int32 Id=1;
required string Name=2;
}
有人可以建议如何反序列化在C#中创建的对象吗?
答案 0 :(得分:3)
Java文档对于反序列化由Java版本序列化的对象有何看法?基本上:“做那个”。序列化数据没有区别。
如果问题是Java示例以.proto文件开头,则使用:
string proto = Serializer.GetProto<Person>();
虽然你展示的.proto看起来很好。
答案 1 :(得分:3)
为在C#中创建的文件创建InputStream
,然后调用
Person.parseFrom(InputStream)
如果您更愿意处理该文件中的字节,则此方法还有其他重载。
如果要实现协议,则需要包含标头以标识字节所代表的数据类型。从那里你只需选择正确的proto来解析数据。
修改强>
这是我创建的用于将id映射到类的类,反之亦然,以帮助开发具有protobufs的协议。如果你没有开发网络传输协议,这可能没什么用,但我很确定你是。
我知道你没有要求这个,但也许你会发现它很有用。
将id注册到所有protobuff生成器,然后检索正确的生成器以在接收时反序列化字节。在发送之前获取每个protobuf对象的正确ID。 ID将包含在每个数据包中,以便您知道每个数据包中的数据类型。 (这里的数据包是抽象的,这也适用于流协议。)
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());
}
}
}
}
用法:
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());
答案 2 :(得分:2)
Protocol Buffers的常用方法是:
.proto
文本文件中定义协议。您在C#中使用的库是特殊的。它不需要.proto
文件开头。相反,您可以通过注释类(或C#中的任何术语)在代码中创建协议。
为了使用Java中的代码生成协议,您需要.proto
文件,因为Java不支持代码中的那种定义。
您可以手动编写.proto
文件或让C#库生成它(请参阅Marc Gravell的回答) - 我建议您生成文件,这样您就不会在定义中出错。
获得该文件后,您可以在protoc
文件上运行protobuf编译器(.proto
)(dowload),它将为您生成.java
文件。该文件具有Person
类以及序列化和解析所需的所有内容。
现在,您在项目中包含protobuf[version].jar
和生成的.java
文件。项目中不需要.proto
文件本身。
完成后,只需使用生成的代码解析文件:
Person person = Person.parseFrom(new FileInputStream(file));
您编写的唯一代码行是上面的代码。
有关Java集成的更多详细信息,请参见官方tutorial