将Newtonsoft JSON序列化为字节数组

15

我想要做的是通过一个字节数组字段发送包含头部对象和压缩数据的JSON。

[JsonObject(MemberSerialization.OptOut)]
public class Message
{
    public Message()
    {
        Header = new Header();
    }

    public Header Header { get; set; }


    public byte[] Data { get; set; }
}

字节数组是gzip压缩的JSON对象,但这并不那么重要。我遇到的问题是,如果我对JSON进行序列化,它会转换为字符串,然后再转换回字节。问题在于,由于序列化字节数组会将其转换为字符串表示形式,因此消息大小会增加相当多。

我受到最大消息大小的限制,并且已经实现了压缩数据的拆分,但当我发送包含压缩数据的Byte数组和未压缩头的JSON时,序列化JSON对象使我远超过消息大小限制。

有没有一种可靠的方法可以直接将JSON对象转换为字节数组。

var stringMessage = JsonConvert.SerializeObject(message,Formatting.None);
var bytes = Encoding.UTF8.GetBytes(stringMessage);

var stringMessage2 = JsonConvert.SerializeObject(message.TransportHeader, Formatting.None);
var bytes2 = Encoding.UTF8.GetBytes(stringMessage2);

Message eventMessage = new Message(bytes);
var bytes3= Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message.Transportdata));

压缩后的数据大小=243905

序列化后的完整JSON字节数=325313

仅标题的字节大小=90

仅压缩数据序列化并转换回字节=325210,(当通过JsonConvert.SerializeObject序列化数据并生成字符串表示时,大小会增加)

很明显,它会显著增加,并且是由字节数组引起的。


如果您使用@ygaradon的答案,请传入一个MemoryStream,然后使用ToArray()获取byte[] - Camilo Terevinto
这不是重复的问题。他的问题是序列化大小意外地高。 - usr
你是否考虑过使用multipart/mixed内容类型将数据通过网络传输,而不是直接使用JSON?将你的JSON放在一个部分中,将二进制数据放在另一个部分中。 - Brian Rogers
JSON部分已经存在,因此可以识别和组合二进制数据。如果没有JSON头,则无法重新组合拆分和压缩的数据。而且我不能单独发送两个数据包,因为没有办法知道哪个头属于哪个包。 - Aistis Taraskevicius
2个回答

7
我找到了一种实现我想要的功能的方法,它不是精确的JSON,而是BSON,也称为二进制JSON。虽然发现这个解决方案纯属运气,但我不确定BSON的知名度如何。
无论如何,Newtonsoft通过Newtonsoft.Json.Bson nuget包支持它,网址是:https://www.nuget.org/packages/Newtonsoft.Json.Bson/1.0.1 以下是一些序列化/反序列化的代码。
foreach (var message in transportMessageList)
{
    MemoryStream ms = new MemoryStream();
    using (BsonDataWriter writer = new BsonDataWriter(ms))
    {
        JsonSerializer serializer = new JsonSerializer();
        serializer.Serialize(writer, message);
    }

    var bsonByteArray = ms.ToArray();
    Assert.True(bsonByteArray.Length!=0);
    bsonList.Add(bsonByteArray);
}

var deserializdTransmortMessageList = new List<TransportMessage>();
foreach (var byteArray in bsonList)
{
    TransportMessage message;
    MemoryStream ms = new MemoryStream(byteArray);
    using (BsonDataReader reader = new BsonDataReader(ms))
    {
        JsonSerializer serializer = new JsonSerializer();
        message = serializer.Deserialize<TransportMessage>(reader);
    }
    Assert.True(message.Transportdata.Length!=0);
    deserializdTransmortMessageList.Add(message);
}

您可以使用与JSON相同的类/对象来处理数据,压缩数组也不会增加其大小。

请注意Newtonsoft网站上的BSON文档已过时,目前仅列出了废弃的API调用。我的代码使用正确的非废弃API调用。


2

JSON是一种基于字符的格式,因此必然涉及字符数据。我猜测您使用了UTF16编码,这使得每个字符变成两个字节。如果您使用UTF8,则不会遇到任何有意义的大小开销。


请贴出您的代码以及您遇到的尺寸扩展类型。 - usr
更新原帖,加入序列化和大小增加。 - Aistis Taraskevicius
@AistisTaraskevicius 謝謝。有多少個字符?不清楚您認為轉換為字節會增加大小的原因是什麼。相對於什麼,您注意到了增加? - usr
如果你看一下帖子底部,我指出压缩后的数据大小为243905字节,当同样的数据被序列化并转换回字节(这样我就可以发送到 Azure)时,大小增加到325210字节。当序列化发生时,它会增加,字符串表示很长,并将其转换回字节对于大小没有任何帮助。 - Aistis Taraskevicius
@AistisTaraskevicius 我明白了... new Message(bytes) 是什么样子的?也许这些字节最终会被序列化为base64,这会使大小增加。你正在进行双重JSON序列化。你是在序列化之前还是之后压缩数据?你应该在序列化之后再进行压缩。然后,压缩应该几乎可以抵消base64大小的增加。 - usr
显示剩余5条评论

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