在我的应用程序中,我有一个包含结构化数据的简单XML格式文件。每个数据条目都有一个数据类型和一个值。像
这样的东西<entry>
<field type="integer">5265</field>
<field type="float">34.23</field>
<field type="string">Jorge</field>
</entry>
现在,这种格式化允许我们以人类可读的形式获取数据,以便检查各种值,以及轻松地执行文件的转换和读取以实现互操作性。
问题是我们有一个非常低带宽的连接(大约1000 bps,是的,每秒的比特数),因此XML并不是传输数据的最佳格式。我正在寻找将xml文件编码为二进制等价物的方法,它更适合传输。
你知道有关这个问题的任何好教程吗?
另外我们在发送之前压缩数据(简单的GZIP)所以如果我去二进制,我有点担心失去压缩比。 尺寸是否会受到影响(压缩时)如此严重,以至于首先尝试对其进行优化会是一个坏主意?
注意:这不是过早优化,这是必需的。 1000 bps是一个非常低的带宽,因此每个字节都很重要。
注2:应用程序是用c#编写的,但任何教程都可以。
答案 0 :(得分:2)
尝试使用ASN.1。打包的编码规则应该自己产生一个相当不错的压缩形式,并且xml编码规则应该产生与你现有的xml相当的东西。
另外,请考虑使用7zip而不是gzip。
答案 1 :(得分:1)
您可能需要调查Google Protocol Buffers。它们产生的有效载荷远远小于XML,尽管不一定是最小的有效载荷;它们是否可以接受使用取决于很多因素。不过,它们肯定比从头设计自己的方案更容易。
They've been ported to C#/.NET并且似乎在我的(迄今为止,有点有限)经历中工作得很好。该链接上有一个包与VS集成,并自动从.proto文件创建C#类,非常好。
答案 2 :(得分:1)
将明文格式转换为二进制格式有效的任何内容都可能使压缩率更差,是的。
然而,无论如何,XML优化的二进制格式可能更好。查看Wikipedia page上列出的各种XML二进制格式。我对WBXML有一些经验,但就是这样。
正如JeeBee所说,老实说,自定义二进制格式可能是最有效的方法。您可以尝试到gzip它,但结果将取决于数据首先是什么样的。
是的,正如Skirwan所说,协议缓冲区在这里是一个相当明显的候选者 - 但您可能想要考虑自定义浮点表示,具体取决于您的实际需求。如果你只需要4SF(并且你知道比例)那么发送一个两字节整数可能是最好的选择。
答案 3 :(得分:1)
我要转储(无论如何,你可以在发送者处解构,并在接收器上重建,在Java中你可以使用自定义的Input / OutputStream来整齐地完成工作)XML。使用固定字段转换为二进制文件 - 数据类型,长度,数据。
假设你有8个或更少的数据类型,用三位编码。然后是长度,例如,作为8位值(0..255)。
然后对于每种数据类型,编码方式不同。
您可能希望在其前面添加要传输的字段总数。如果传输是有损的,则执行CRC或8/10编码,但希望系统已经处理过。
但是,不要低估XML文本的压缩程度。我当然会做一些计算来检查实现了多少压缩。
答案 4 :(得分:1)
首先要尝试的是gzip;除此之外,我会尝试使用protobuf-net - 我可以很容易地想到几种编码方式,但这取决于你是如何构建xml的,以及你是否介意在两种格式之间使用一些代码来进行填充。特别是,我可以想象将不同的数据类型表示为 3个可选字段在同一类型上,或 3个不同的抽象契约子类。
[ProtoContract]
class EntryItem {
[ProtoMember(1)]
public int? Int32Value {get;set;}
[ProtoMember(2)]
public float? SingleValue {get;set;}
[ProtoMember(3)]
public string StringValue {get;set;}
}
[ProtoContract]
class Entry {
[ProtoMember(1)]
public List<EntryItem> Items {get; set;}
}
通过测试:
[TestFixture]
public class TestEntries {
[Test]
public void ShowSize() {
Entry e = new Entry {
Items = new List<EntryItem>{
new EntryItem { Int32Value = 5265},
new EntryItem { SingleValue = 34.23F },
new EntryItem { StringValue = "Jorge" }
}
};
var ms = new MemoryStream();
Serializer.Serialize(ms, e);
Console.WriteLine(ms.Length);
Console.WriteLine(BitConverter.ToString(ms.ToArray()));
}
}
结果(21个字节)
0A-03-08-91-29-0A-05-15-85-EB-08-42-0A-07-1A-05-4A-6F-72-67-65
答案 5 :(得分:1)
我会考虑配置您的应用以响应较小的XML片段;特别是那些足够小以适合单个网络数据包的。
然后按照对用户重要性的顺序排列您的数据,以便他们可以看到有用的东西,甚至可以在所有数据到达之前开始处理它。
答案 6 :(得分:1)
迟到的反应 - 至少在年底前到来; - )
你提到了Fast Infoset。你试过吗?它应该在紧凑性和性能方面给你最好的结果。添加GZIP压缩,最终大小将非常小,您将避免压缩XML的处理代价。 WCF-Xtensions也提供Fast Infoset消息编码和GZIP / DEFLATE / LZMA / PPM压缩(适用于.NET / CF / SL / Azure)。
答案 7 :(得分:0)
这是你所处的腌菜:你正在用Gzip压缩。 Gzip在纯文本上是可怕的,直到你达到狄更斯的总连续作品的长度或大约1200行代码。字典的开销和Gzip用于压缩的其他东西。
对于7500个字符的任务,1Kbps是好的(在最佳条件下需要大约一分钟,但对于<300个字符,你应该没事!)但是如果你真的那么担心,那么你要去为了简洁起见,想要压缩它。以下是我如何做这种规模的事情:
T[ype]L[ength][data data data]+
即,T代表TYPE。对于INT表示0x01,对于STRING表示0x02等.LENGTH只是一个int ...所以0xFF = 254个字符长等等。示例数据包看起来像:
0x01 0x01 0x3F 0x01 0x01 0x2D 0x02 0x06 H E L L O 0x00
这表示我有一个INT,长度为1,值为0x3F,一个INT,长度为1,值为0x2D,然后是一个STRING,长度为6的空终止“HELLO”(假设为Ascii)。学习System.Text.Encoding.Utf8.getBytes和BitConverter以及ByteConverter的奇迹。
供参考 请参阅This page,了解1Kbps的数量。真的,对于你正在处理的大小,你应该没问题。