Запись на чтение с 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 не читаем».

Я, наверное, все испортил, поэтому все ответы приветствуются. Благодарю.

Три вещи:

  • Не закрывайте StreamWriter . Это закроет MemoryStream . Однако вам нужно очистить писателя.
  • Сбросьте положение 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(); } } 

Однако есть еще одна более простая альтернатива. Все, что вы делаете с streamом, когда чтение преобразует его в строку. Вы можете сделать это проще:

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

К сожалению, MemoryStream.Length будет бросать, если stream был закрыт, поэтому вы, вероятно, захотите вызвать конструктор StreamWriter , который не закрывает базовый stream, или просто не закрывать StreamWriter .

Меня беспокоит, что вы пишете прямо в stream – что такое ser ? Является ли это сериализатором XML или двоичным? Если он двоичный, ваша модель несколько ошибочна – вы не должны смешивать двоичные и текстовые данные, не будучи очень осторожными. Если это XML, вы можете обнаружить, что в конце строки вы попадаете в байты байтов, что может быть проблематичным.

установка позиции streamов памяти в начало может помочь.

  stream.Position = 0; 

Но основная проблема заключается в том, что StreamWriter закрывает ваш 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.

Чтобы получить доступ к содержимому MemoryStream после его закрытия, используйте ToArray() или GetBuffer() . Следующий код демонстрирует, как получить содержимое буфера памяти как кодированную строку UTF8.

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

Примечание. ToArray() проще использовать, чем GetBuffer() потому что ToArray() возвращает точную длину streamа, а не размер буфера (который может быть больше, чем stream). ToArray() делает копию байтов.

Примечание. GetBuffer() более эффективен, чем ToArray() , поскольку он не делает копию байтов. Вам нужно позаботиться о возможных неопределенных байтах конца в конце буфера, считая длину streamа, а не размер буфера. Использование GetBuffer() настоятельно рекомендуется, если размер streamа больше 80000 байт, потому что копия ToArray будет выделена в кучке больших объектов, где ее жизненное время может стать проблематичным.

Также возможно клонировать исходный MemoryStream следующим образом, чтобы облегчить доступ к нему через StreamReader, например

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

Идеальным решением является доступ к исходному MemoryStream до его закрытия, если это возможно.

Просто дикое предположение: может быть, вам нужно сбросить streamовик? Возможно, система видит, что есть записи «ожидающие». По смыванию вы точно знаете, что stream содержит все написанные символы и читается.