[英]Serialize/Deserialize Large DataSet
我有一个报告工具,可将查询请求发送到服务器。 服务器完成查询后,结果将发送回请求报告工具。 使用WCF完成通信。
存储在DataSet对象中的查询数据非常大,通常约为100mb。
为了加快传输速度,我进行了序列化(BinaryFormatter)并压缩了DataSet。服务器和报表工具之间传输的对象是字节数组。
但是,在几次请求之后,报表工具尝试对数据集进行反序列化时会引发OutOfMemoryException。 当我打电话时抛出异常:
dataSet = (DataSet) formatter.Deserialize(dstream);
dstream是DeflateStream,用于解压缩传输的压缩字节数组。
异常发生在formatter的子调用中。从流中创建字节数组时,请反序列化。
还有其他任何更好的机制来防止此异常的二进制序列化方式吗?
执行:
序列化和压缩数据集的方法(由服务器使用)
public static byte[] Compress(DataSet dataSet)
{
using (var input = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(input, dataSet);
using (var output = new MemoryStream())
{
using (var compressor = new DeflateStream(output, CompressionLevel.Optimal))
{
input.Position = 0;
var buffer = new byte[1024];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
compressor.Write(buffer, 0, read);
compressor.Close();
return output.ToArray();
}
}
}
}
解压缩和反序列化DataSet的方法(由报表工具使用)
public static DataSet Decompress(byte[] data)
{
DataSet dataSet;
using (var input = new MemoryStream(data))
{
using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
{
var formatter = new BinaryFormatter();
dataSet = (DataSet) formatter.Deserialize(dstream);
}
}
return dataSet;
}
堆栈跟踪:
at System.Array.InternalCreate(Void* elementType, Int32 rank, Int32* pLengths, Int32* pLowerBounds)
at System.Array.CreateInstance(Type elementType, Int32 length)
at System.Array.UnsafeCreateInstance(Type elementType, Int32 length)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseArray(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObject(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at DRX.PTClientMonitoring.Infrastructure.Helper.DataSetCompressor.Decompress(Byte[] data) in c:\_develop\PTClientMonitoringTool\PTClientMonitoringTool\Source\DRX.PTClientMonitoring.Infrastructure\Helper\DataSetCompressor.cs:line 51
at DRX.PTClientMonitoring.Reporting.ViewModels.ShellViewModel.<>c__DisplayClassf.<ExecudeDefinedQuery>b__4() in c:\_develop\PTClientMonitoringTool\PTClientMonitoringTool\Source\DRX.PTClientMonitoring.Reporting\ViewModels\ShellViewModel.cs:line 347
序列化之前,请设置:
yourDataSet.RemotingFormat = SerializationFormat.Binary;
那应该有很大帮助。 即使使用BinaryFormatter
,默认值也是xml。
但是请注意, DataSet
和DataTable
本质上不是优化的最佳选择。 有很多伟大的序列化工具,将做包装你的数据的一个更好的工作,但他们不变的需要强大的款型,即List<SomeSpecificType>
其中SomeSpecificType
是POCO / DTO类。 甚至WCF也几乎不能容忍DataTable
/ DataSet
。 因此,如果您可以摆脱对DataTable
/ DataSet
依赖,我强烈建议您这样做。
另一种选择是将数据作为Stream
发送 。 我很确定WCF本身就支持此功能,但是从理论上讲,这将使您拥有一个实际上更大得多的不同Stream
( 不是 MemoryStream
)。 作为一种便宜的选择,您可以将临时文件用作暂存区域,但是如果可行,您可以研究将多个缓冲区缝合在一起的自定义内存流。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.