使用 c# 的 protobuf 反序列化“长”字符串对我来说不起作用

Posted

技术标签:

【中文标题】使用 c# 的 protobuf 反序列化“长”字符串对我来说不起作用【英文标题】:deserialize "long" string with protobuf for c# doesn't work properly for me 【发布时间】:2011-10-14 22:16:41 【问题描述】:

我显然做错了一些基本错误,但我无法弄清楚并且找不到文档。

我正在试验 Marc Gravell 的 .NET 的 proto-buf,并尝试序列化和反序列化对象。一旦一个对象包含一个“太长”的字符串(没有尝试确定大小阈值,但它只有几百字节),该字符串就无法正确反序列化。

这是我的代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using ProtoBuf;

namespace ConsoleApplication1

public class Program

    [ProtoContract]
    public class test
    
        [ProtoMember(1)]            
        public int i;
        [ProtoMember(2)]
        public string s1;
        [ProtoMember(3)]
        public string s2;
        [ProtoMember(4)]
        public char[] arrchars;
        [ProtoMember(5)]
        public Dictionary<int, string> Dict = new Dictionary<int, string>();

    


    static void Main(string[] args)
    
        test var1 = new test();
        var1.i = 10;
        var1.s1 = "Hello";
        var1.arrchars = new char[] 'A', 'B', 'C';
        var1.Dict.Add(10, "ten");
        var1.Dict.Add(5, "five");
        var1.s2 = new String('X', 520);

        string s = PBSerializer.Serialize(typeof (test), var1);

        test var2 = null;
        PBSerializer.Deserialize(s, out var2);
    


    public static class PBSerializer
    
        public static string Serialize(Type objType, object obj)
        
            MemoryStream stream = new MemoryStream();
            ProtoBuf.Serializer.Serialize(stream, obj);
            // ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, obj, PrefixStyle.Fixed32, 1);
            stream.Flush();
            stream.Position = 0;
            StreamReader sr = new StreamReader(stream);
            string res = sr.ReadToEnd();
            stream.Dispose();
            sr.Dispose();
            return res;
        

        public static void Deserialize(string serializedObj, out test obj)
        
            MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(serializedObj));
            obj = ProtoBuf.Serializer.Deserialize<test>(stream);
            // obj = ProtoBuf.Serializer.DeserializeWithLengthPrefix<test>(stream, PrefixStyle.Fixed32, 1);
            stream.Dispose();
        

    



var2.s2 与 var1.s2 不同 - 它在字符串的开头有一个额外的字符,并截断了字符串结尾的大部分内容。但是,如果我将 var1.s2 的长度更改为一个小数字(比如 52 而不是 520 个字符),我的问题就会消失,但我需要能够序列化长字符串。 我认为这与我在设置 PrefixStyle (?) 时做错了什么有关,或者我没有使用正确的编码 (?)。但是,反复试验并没有帮助我解决问题。

我正在使用 .NET 3.5 并尝试使用 444 和 450 版本,结果相同。

谢谢。

【问题讨论】:

强调乔恩的观点:marcgravell.blogspot.com/2010/03/binary-data-and-strings.html - 这不是一个罕见的错误;我经常看到这种情况 感谢 Marc 的链接,非常感谢 .NET 的 protobuf。 【参考方案1】:

您正在序列化 二进制 数据 - 但随后尝试将其作为文本读取。不是 - 所以不要那样做。

如果您将任意二进制数据转换为文本,请使用Convert.ToBase64StringConvert.FromBase64String

public static class PBSerializer

    public static string Serialize(Type objType, object obj)
    
        using (MemoryStream stream = new MemoryStream())
        
            ProtoBuf.Serializer.Serialize(stream, obj);
            return Convert.ToBase64String(stream.ToArray());
        
    

    // Ideally change this to use a return value instead of an out parameter...
    public static void Deserialize(string serializedObj, out test obj)
    
        byte[] data = Convert.FromBase64String(serializedObj);
        using (MemoryStream stream = new MemoryStream(data))
        
            obj = ProtoBuf.Serializer.Deserialize<test>(stream);
        
    

【讨论】:

我每隔几周就会收到至少的人发来的电子邮件。在某些方面,我真的应该添加一个基于字符串的重载...... 非常感谢,乔恩·斯基特。现在好了,我明白我的错误了。

以上是关于使用 c# 的 protobuf 反序列化“长”字符串对我来说不起作用的主要内容,如果未能解决你的问题,请参考以下文章

C# Protobuf-net:如何从网络流中连续反序列化?

Protobuf-net 使用嵌套数据反序列化时出现无效的线型异常(C++ 到 C#)

通讯协议及Google.Protobuf生成c#代码 序列及反序列化

protobuf-net 不使用私有设置器序列化 C# 属性

使用 Protobuf 和内存映射文件 C# 的 IPC

使用 protobuf-net,是不是可以在不分配内存的情况下反序列化消息?