写入然后从MemoryStream读取
我正在使用DataContractJsonSerializer
,它喜欢输出到一个stream。 我想上下拖动序列化器的输出,所以我使用StreamWriter交替地写入我需要的额外位。
var ser = new DataContractJsonSerializer(typeof (TValue)); using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream)) { sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); ser.WriteObject(stream, kvp.Value); } sw.Write("}"); } using (var streamReader = new StreamReader(stream)) { return streamReader.ReadToEnd(); } }
当我这样做时,我得到一个ArgumentException
“stream不可读”。
我可能在这里各种各样的错误,所以所有的答案欢迎。 谢谢。
三件事:
- 不要closures
StreamWriter
。 这将closuresMemoryStream
。 你确实需要刷新作者。 - 在读取之前重置stream的位置。
- 如果您要直接写入stream,则需要先刷新写入器。
所以:
using (var stream = new MemoryStream()) { var sw = new StreamWriter(stream); sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); sw.Flush(); ser.WriteObject(stream, kvp.Value); } sw.Write("}"); sw.Flush(); stream.Position = 0; using (var streamReader = new StreamReader(stream)) { return streamReader.ReadToEnd(); } }
还有另一个更简单的select。 当读取将其转换为string时,您正在处理stream。 你可以更简单地做到这一点:
return Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int) stream.Length);
不幸的是,如果stream已closures, MemoryStream.Length
将抛出,因此您可能需要调用不closures底层stream的StreamWriter
构造函数,或者不要closuresStreamWriter
。
我担心你直接写信给这个stream – 什么是ser
? 它是一个XML序列化程序,还是一个二进制的? 如果它是二进制的,那么你的模型有点缺陷 – 你不应该混淆二进制文本和文本数据,而不会非常小心。 如果是XML,你可能会发现你的string中间会出现字节顺序标记,这可能是有问题的。
设置内存stream的位置可能会有所帮助。
stream.Position = 0;
但是,核心问题是StreamWriter在closures时正在closures内存stream。
简单地刷新那个stream,在那里你结束使用的块,只有在处理完之后才能从内存stream中读取数据,这将为你解决这个问题。
你也可以考虑使用StringWriter来代替…
using (var writer = new StringWriter()) { using (var sw = new StreamWriter(stream)) { sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); ser.WriteObject(writer, kvp.Value); } sw.Write("}"); } return writer.ToString(); }
这将要求您的序列化WriteObject调用可以接受TextWriter而不是Stream。
在closures之后访问MemoryStream的内容使用ToArray()
或GetBuffer()
方法。 以下代码演示如何以UTF8编码string的forms获取内存缓冲区的内容。
byte[] buff = stream.ToArray(); return Encoding.UTF8.GetString(buff,0,buff.Length);
注意: ToArray()
比GetBuffer()
更简单,因为ToArray()
返回stream的确切长度,而不是缓冲区大小(可能大于stream内容)。 ToArray()
创build一个字节的副本。
注意: GetBuffer()
比ToArray()
更ToArray()
,因为它不会复制字节。 您需要考虑stream的长度而不是缓冲区的大小来关注可能的未定义的尾部字节。 如果stream大小大于80000字节,则强烈build议使用GetBuffer()
因为ToArray副本将分配到大对象堆,其生命周期可能会出现问题。
也可以如下克隆原始的MemoryStream,以便于通过StreamReader访问它,例如,
using (MemoryStream readStream = new MemoryStream(stream.ToArray())) { ... }
如果可能,理想的解决scheme是在closures之前访问原始的MemoryStream。
只是一个疯狂的猜测:也许你需要冲洗的Streamwriter? 系统可能会看到写入“正在等待”。 通过刷新你知道,确保该stream包含所有书面字符,并可读。