Program Club

MemoryStream에 쓰기 후 읽기

proclub 2020. 12. 7. 21:07
반응형

MemoryStream에 쓰기 후 읽기


나는 DataContractJsonSerializer스트림으로 출력하는 것을 좋아하는을 사용하고 있습니다. 직렬화 기의 출력을 상단 및 꼬리로 지정하여 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"스트림을 읽을 수 없습니다"라는 메시지가 나타납니다.

나는 아마 여기에서 모든 종류의 잘못을하고 있으므로 모든 답변을 환영합니다. 감사.


세개:

  • 을 닫지 마십시오 StreamWriter. 그러면 MemoryStream. 그래도 작가를 플러시해야합니다.
  • 읽기 전에 스트림의 위치를 ​​재설정하십시오.
  • 스트림에 직접 쓰려면 먼저 라이터를 플러시해야합니다.

그래서:

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();
    }
}

그래도 더 간단한 대안이 있습니다. 읽을 때 스트림으로하는 모든 작업은 문자열로 변환하는 것입니다. 더 간단하게 할 수 있습니다.

return Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int) stream.Length);

Unfortunately MemoryStream.Length will throw if the stream has been closed, so you'd probably want to call the StreamWriter constructor that doesn't close the underlying stream, or just don't close the StreamWriter.

I'm concerned by you writing directly to the the stream - what is ser? Is it an XML serializer, or a binary one? If it's binary, your model is somewhat flawed - you shouldn't mix binary and text data without being very careful about it. If it's XML, you may find that you end up with byte-order marks in the middle of your string, which could be problematic.


setting the memory streams position to the beginning might help.

 stream.Position = 0; 

But the core problem is that the StreamWriter is closing your memory stream when it is closed.

Simply flushing that stream where you end the using block for it and only disposing of it fter you have read the data out of the memory stream will solve this for you.

You may also want to consider using a StringWriter instead...

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();
}

This would require your serialization WriteObject call can accept a TextWriter instead of a Stream.


To access the content of a MemoryStream after it has been closed use the ToArray() or GetBuffer() methods. The following code demonstrates how to get the content of the memory buffer as a UTF8 encoded string.

byte[] buff = stream.ToArray(); 
return Encoding.UTF8.GetString(buff,0,buff.Length);

Note: ToArray() is simpler to use than GetBuffer() because ToArray() returns the exact length of the stream, rather than the buffer size (which might be larger than the stream content). ToArray() makes a copy of the bytes.

Note: GetBuffer() is more performant than ToArray(), as it doesn't make a copy of the bytes. You do need to take care about possible undefined trailing bytes at the end of the buffer by considering the stream length rather than the buffer size. Using GetBuffer() is strongly advised if stream size is larger than 80000 bytes because the ToArray copy would be allocated on the Large Object Heap where it's lifetime can become problematic.

It is also possible to clone the original MemoryStream as follows, to facilitate accessing it via a StreamReader e.g.

using (MemoryStream readStream = new MemoryStream(stream.ToArray()))
{
...
}

The ideal solution is to access the original MemoryStream before it has been closed, if possible.


Just a wild guess: maybe you need to flush the streamwriter? Possibly the system sees that there are writes "pending". By flushing you know for sure that the stream contains all written characters and is readable.

참고URL : https://stackoverflow.com/questions/1232443/writing-to-then-reading-from-a-memorystream

반응형