有人能给我很好的解释为什么会失败吗?
const int bufferSize = 2 * 1024, testValue = 123456;
var buffer = new byte[bufferSize];
var serializer = new DataContractSerializer(typeof(int));
//Serialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(memStream))
serializer.WriteObject(writer, testValue);
//Deserialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max))
{
object deserializedValue = serializer.ReadObject(reader); // <--- nope, this throws System.Runtime.Serialization.SerializationException: The input source is not correctly formatted.
Console.WriteLine(deserializedValue);
}
我正在使用共享内存 IPC,其中一部分意味着您必须处理固定大小的进程间缓冲区。我正在将对象序列化到缓冲区中,并且我想变得很酷,所以我尝试使用 DataContractSerializer + 二进制 XmlDictionaryWriter 组合,这是我所知道的最快的非自定义序列化技术之一。 问题是反序列化时,XmlDictionaryReader 似乎试图将整个内存流视为一个大的 xml 文档,并读取它自己的流结束/ block 标记,遇到大堆零,然后简单地自行崩溃。 BinaryFormatter 不存在这个问题,因为它逐 block 读取流。 我不得不想出一个相当蹩脚的解决方案来实现自定义流,该解决方案在到达第一个 0 后“伪造”流的结尾(假设是 XmlDictionaryWriter 的 eof 标记)。
完整演示:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
namespace SerializationTest
{
public static class Program
{
public static void Main()
{
const int bufferSize = 2 * 1024, testValue = 123456;
var buffer = new byte[bufferSize];
var serializer = new DataContractSerializer(typeof(int));
//Serialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(memStream))
serializer.WriteObject(writer, testValue);
//Deserialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max))
{
object deserializedValue = serializer.ReadObject(reader); // <--- nope, this throws System.Runtime.Serialization.SerializationException: The input source is not correctly formatted.
Console.WriteLine(deserializedValue);
}
//Deserialize value via FakeEndStream
using (var memStream = new FakeEndStream(new MemoryStream(buffer)))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max))
{
object deserializedValue = serializer.ReadObject(reader);
Console.WriteLine(deserializedValue);
}
}
private sealed class FakeEndStream : Stream
{
private readonly Stream _source;
private bool _endOfStream;
public FakeEndStream(Stream source)
{
_source = source;
}
#region The workaround
public override int Read(byte[] buffer, int offset, int count)
{
int i = 0;
for (int position = offset; i < count; i++, position++)
{
int value = ReadByte();
if (value < 0)
return i;
buffer[position] = (byte)value;
}
return i;
}
public override int ReadByte()
{
if (_endOfStream)
return -1;
int value = _source.ReadByte();
if (value <= 0)
_endOfStream = true;
return value;
}
#endregion
#region Boilerplate overrides of Stream
protected override void Dispose(bool disposing)
{
_source.Dispose();
}
public override void Flush()
{
_source.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return _source.Seek(offset, origin);
}
public override void SetLength(long value)
{
_source.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_source.Write(buffer, offset, count);
}
public override bool CanRead
{
get { return _source.CanRead; }
}
public override bool CanSeek
{
get { return _source.CanSeek; }
}
public override bool CanWrite
{
get { return _source.CanWrite; }
}
public override long Length
{
get { return _source.Length; }
}
public override long Position
{
get { return _source.Position; }
set { _source.Position = value; }
}
#endregion
}
}
}
最佳答案
当然,我会帮助你解决这个问题(因为没有其他人愿意去确认/否认这些症状)。
我发现问题确实是读者读取了无效数据。但是,您可以通过在流末尾写入空格来帮助它,如下所示:
//Serialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(memStream))
{
serializer.WriteObject(writer, testValue);
writer.WriteWhitespace(" ");
}
//Deserialize value
using (var memStream = new MemoryStream(buffer))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max))
{
object deserializedValue = serializer.ReadObject(reader); // \o/
Console.WriteLine(deserializedValue);
}
不敢相信没有人喜欢这个问题,因为它可能会导致运行时难以调试异常,从而使使用 XmlDictionaryWriter 序列化对象变得有点不可靠。
关于c# - XmlDictionaryReader 读取固定大小的归零流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20429484/