C# 考虑流大小限制的.NET序列化
我正在序列化一个对象,它有几个子对象(也可以序列化)。我可以在序列化过程之间检查流的大小吗?(我只想限制我正在序列化的流的大小)不使用任何内置类,但您可以轻松地创建具有此限制的流包装器类 您可以这样简单地使用它:C# 考虑流大小限制的.NET序列化,c#,.net,serialization,C#,.net,Serialization,我正在序列化一个对象,它有几个子对象(也可以序列化)。我可以在序列化过程之间检查流的大小吗?(我只想限制我正在序列化的流的大小)不使用任何内置类,但您可以轻松地创建具有此限制的流包装器类 您可以这样简单地使用它: Stream limitedStream = new LimitedStream(realStream, 10 * 1024 * 1024); // 10MB max 然后序列化到该位置。根据序列化程序的不同,可以将项目独立地放到流的末尾(并且仍然可以再次读取流)。不是“纯”xml(
Stream limitedStream = new LimitedStream(realStream, 10 * 1024 * 1024); // 10MB max
然后序列化到该位置。根据序列化程序的不同,可以将项目独立地放到流的末尾(并且仍然可以再次读取流)。不是“纯”xml(由于根元素),但我知道至少有一个序列化程序支持顺序对象读/写(猜测哪一个没有好处) 如果大小是绝对关键的,那么可以通过
MemoryStream
——类似(伪代码)的方式
工作完成了。这避免了通过将每个单独的对象完成到内存流中来写入部分对象(尽可能重用底层内存),因此只有在知道数据适合时才将数据复制到实际的流中
下面是一个完整的示例,使用:
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Xml.Serialization;
使用ProtoBuf;
[XmlType]//没有实际序列化为xml;只是它需要
类MyData//一种识别成员的方法,它支持
{//通过XmlType/xmlement指定Order属性
[xmlement(Order=1)]公共int-Id{get;set;}
[XmlElement(Order=2)]公共字符串名称{get;set;}
}
静态类程序
{
静态IEnumerable GetItems()
{
Random rand=新的Random();
整数计数=0;
while(true)//数据的无限序列;mwahaahahah
{
新MyData的收益回报率
{
Id=rand.Next(0,5000),
Name=“Item”+计数++
};
}
}
静态void Main()
{
int space=2048,count=0;
长校验和=0;
使用(Stream dest=File.Create(“out.bin”))
使用(MemoryStream buffer=new MemoryStream())
{
foreach(GetItems()中的MyData对象)
{
SetLength(0);//重置为空,但保留缓冲区以减少allocs
Serializer.SerializeWithLengthPrefix(缓冲区,对象,PrefixStyle.Base128,1);
int len=(int)buffer.Length;
if(buffer.Length ok thanq.那么,如果将10mb的数据写入流,并且仍然存在要序列化的对象的某些其他属性,会发生什么情况呢?它会引发异常吗?我会编写该流类,以便在达到10mb时引发异常,是的。
using(Stream dest = ... )
using(MemoryStream buffer = new MemoryStream())
{
foreach(SomeType obj in items) {
buffer.SetLength(0); // reset to empty, but retaining buffer to reduce allocs
someSerializer.Serialize(buffer, obj);
if(enoughSpace) {
// add our item
dest.Write(buffer.GetBuffer(), 0, buffer.Length);
// TODO: decrement space
} else {
break; // or new file, whatever
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using ProtoBuf;
[XmlType] // not actually serialized as xml; simply it needs
class MyData // a way of identifying the members, and it supports
{ // the Order property via XmlType/XmlElement
[XmlElement(Order = 1)] public int Id { get; set; }
[XmlElement(Order = 2)] public string Name { get; set; }
}
static class Program
{
static IEnumerable<MyData> GetItems()
{
Random rand = new Random();
int count = 0;
while (true) // an infinite sequence of data; mwahahaahah
{
yield return new MyData
{
Id = rand.Next(0, 5000),
Name = "Item " + count++
};
}
}
static void Main()
{
int space = 2048, count = 0;
long checksum = 0;
using(Stream dest = File.Create("out.bin"))
using(MemoryStream buffer = new MemoryStream())
{
foreach (MyData obj in GetItems())
{
buffer.SetLength(0); // reset to empty, but retaining buffer to reduce allocs
Serializer.SerializeWithLengthPrefix(buffer, obj, PrefixStyle.Base128, 1);
int len = (int)buffer.Length;
if(buffer.Length <= space) {
// add our item
dest.Write(buffer.GetBuffer(), 0, len);
space -= len;
checksum += obj.Id;
count++;
} else {
break; // or new file, whatever
}
}
}
Console.WriteLine("Wrote " + count + " objects; chk = " + checksum);
using (Stream source = File.OpenRead("out.bin"))
{
count = 0;
checksum = 0;
foreach (MyData item in
Serializer.DeserializeItems<MyData>(source, PrefixStyle.Base128, 1))
{
count++;
checksum += item.Id;
}
}
Console.WriteLine("Read " + count + " objects; chk = " + checksum);
}
}