写入然后从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不可读”。

我可能在这里各种各样的错误,所以所有的答案欢迎。 谢谢。

三件事:

  • 不要closuresStreamWriter 。 这将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包含所有书面字符,并可读。