繁体   English   中英

序列化/反序列化大数据集

[英]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。

但是请注意, DataSetDataTable 本质上不是优化的最佳选择。 有很多伟大的序列化工具,将做包装你的数据的一个更好的工作,但他们不变的需要强大的款型,即List<SomeSpecificType>其中SomeSpecificType是POCO / DTO类。 甚至WCF也几乎不能容忍DataTable / DataSet 因此,如果您可以摆脱对DataTable / DataSet依赖,我强烈建议您这样做。

另一种选择是将数据作为Stream发送 我很确定WCF本身就支持此功能,但是从理论上讲,这将使您拥有一个实际上更大得多的不同Stream不是 MemoryStream )。 作为一种便宜的选择,您可以将临时文件用作暂存区域,但是如果可行,您可以研究将多个缓冲区缝合在一起的自定义内存流。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM