Как вы получаете строку из MemoryStream?

453

Если мне задан MemoryStream, который, как я знаю, был заполнен с помощью String, как мне получить String обратно?

  • 1
    Никогда не уверен, всегда ли требуется reader.close. У меня были проблемы в прошлом, поэтому, как правило, я всегда стараюсь быть на всякий случай.
Теги:
string
memorystream

10 ответов

405
Лучший ответ

В этом примере показано, как читать и записывать строку в MemoryStream.


static void Main(string[] args)
{
    using (var ms = new MemoryStream())
    {
        var sw = new StreamWriter(ms);
        sw.WriteLine("Hello World");
        // The string is currently stored in the 
        // StreamWriters buffer. Flushing the stream will 
        // force the string into the MemoryStream.
        sw.Flush();

        // If we dispose the StreamWriter now, it will close 
        // the BaseStream (which is our MemoryStream) which 
        // will prevent us from reading from our MemoryStream
        //DON'T DO THIS - sw.Dispose();

        // The StreamReader will read from the current 
        // position of the MemoryStream which is currently 
        // set at the end of the string we just wrote to it. 
        // We need to set the position to 0 in order to read 
        // from the beginning.
        ms.Position = 0;
        var sr = new StreamReader(ms);
        var myStr = sr.ReadToEnd();
        Console.WriteLine(myStr);
    }

    Console.WriteLine("Press any key to continue.");
    Console.ReadKey();
}
  • 3
    Разве он не собирается утилизировать StreamWriter, когда функция выходит из области видимости?
  • 12
    Dispose не вызывается, когда переменная выходит из области видимости. Finalize будет вызван, когда GC доберется до него, но Dispose - это то, что необходимо вызвать, прежде чем переменная выйдет из области видимости. Я не называю это выше, потому что я знаю, что реализация StreamWriter и StreamReader не требуют вызова Dispose, он просто передает вызов базовому потоку. Тем не менее, можно обоснованно аргументировать вызов Dipose для всего, что реализует IDisposable, поскольку вы не можете гарантировать, что будущий выпуск не потребует его утилизации.
Показать ещё 3 комментария
210

Вы также можете использовать

Encoding.ASCII.GetString(ms.ToArray());

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

  • 21
    +1: идеально подходит для юнит-тестирования, спасибо.
  • 6
    Кодировка находится в пространстве имен System.Text
Показать ещё 4 комментария
100

Использование StreamReader для преобразования MemoryStream в строку.

<Extension()> _
Public Function ReadAll(ByVal memStream As MemoryStream) As String
    ' Reset the stream otherwise you will just get an empty string.
    ' Remember the position so we can restore it later.
    Dim pos = memStream.Position
    memStream.Position = 0

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' Reset the position so that subsequent writes are correct.
    memStream.Position = pos

    Return str
End Function
  • 3
    Установка позиции в 0 ограничивает возможность повторного использования метода - лучше всего, чтобы вызывающая сторона управляла этим. Что если поток содержит данные до строки, которые вызывающий знает, как обрабатывать?
  • 1
    Оператор using гарантирует удаление вашего StreamReader, но в документации говорится, что StreamReader закрывает основной поток при его удалении. Следовательно, ваш метод закрывает MemoryStream, который ему передают, что концептуально не охлаждает для вызывающих, даже если я сомневаюсь, что MemoryStream.Dispose делает многое.
Показать ещё 2 комментария
31

используйте StreamReader, затем вы можете использовать ReadToEnd, который возвращает строку.

  • 11
    Я просто хочу упомянуть, что Basestream должен установить свою позицию в 0. Like memoryStream.Position = 0; ,
17

Предыдущие решения не будут работать в случаях, когда используется кодирование. Вот - вид "реальной жизни" - пример того, как это сделать правильно...

using(var stream = new System.IO.MemoryStream())
{
  var serializer = new DataContractJsonSerializer(typeof(IEnumerable<ExportData>),  new[]{typeof(ExportData)}, Int32.MaxValue, true, null, false);               
  serializer.WriteObject(stream, model);  


  var jsonString = Encoding.Default.GetString((stream.ToArray()));
}
  • 0
    спасибо, я искал этот конкретный сценарий :)
10

В этом примере показано, как читать строку из MemoryStream, в которой я использовал сериализацию (используя DataContractJsonSerializer), передать строку с некоторого сервера на клиент, а затем, как восстановить MemoryStream из строки, переданной как параметр, затем десериализуйте MemoryStream.

Я использовал части разных сообщений для выполнения этого примера.

Надеюсь, что это поможет.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading;

namespace JsonSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var phones = new List<Phone>
            {
                new Phone { Type = PhoneTypes.Home, Number = "28736127" },
                new Phone { Type = PhoneTypes.Movil, Number = "842736487" }
            };
            var p = new Person { Id = 1, Name = "Person 1", BirthDate = DateTime.Now, Phones = phones };

            Console.WriteLine("New object 'Person' in the server side:");
            Console.WriteLine(string.Format("Id: {0}, Name: {1}, Birthday: {2}.", p.Id, p.Name, p.BirthDate.ToShortDateString()));
            Console.WriteLine(string.Format("Phone: {0} {1}", p.Phones[0].Type.ToString(), p.Phones[0].Number));
            Console.WriteLine(string.Format("Phone: {0} {1}", p.Phones[1].Type.ToString(), p.Phones[1].Number));

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var stream1 = new MemoryStream();
            var ser = new DataContractJsonSerializer(typeof(Person));

            ser.WriteObject(stream1, p);

            stream1.Position = 0;
            StreamReader sr = new StreamReader(stream1);
            Console.Write("JSON form of Person object: ");
            Console.WriteLine(sr.ReadToEnd());

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var f = GetStringFromMemoryStream(stream1);

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            Console.WriteLine("Passing string parameter from server to client...");

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            var g = GetMemoryStreamFromString(f);
            g.Position = 0;
            var ser2 = new DataContractJsonSerializer(typeof(Person));
            var p2 = (Person)ser2.ReadObject(g);

            Console.Write(Environment.NewLine);
            Thread.Sleep(2000);

            Console.WriteLine("New object 'Person' arrived to the client:");
            Console.WriteLine(string.Format("Id: {0}, Name: {1}, Birthday: {2}.", p2.Id, p2.Name, p2.BirthDate.ToShortDateString()));
            Console.WriteLine(string.Format("Phone: {0} {1}", p2.Phones[0].Type.ToString(), p2.Phones[0].Number));
            Console.WriteLine(string.Format("Phone: {0} {1}", p2.Phones[1].Type.ToString(), p2.Phones[1].Number));

            Console.Read();
        }

        private static MemoryStream GetMemoryStreamFromString(string s)
        {
            var stream = new MemoryStream();
            var sw = new StreamWriter(stream);
            sw.Write(s);
            sw.Flush();
            stream.Position = 0;
            return stream;
        }

        private static string GetStringFromMemoryStream(MemoryStream ms)
        {
            ms.Position = 0;
            using (StreamReader sr = new StreamReader(ms))
            {
                return sr.ReadToEnd();
            }
        }
    }

    [DataContract]
    internal class Person
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public DateTime BirthDate { get; set; }
        [DataMember]
        public List<Phone> Phones { get; set; }
    }

    [DataContract]
    internal class Phone
    {
        [DataMember]
        public PhoneTypes Type { get; set; }
        [DataMember]
        public string Number { get; set; }
    }

    internal enum PhoneTypes
    {
        Home = 1,
        Movil = 2
    }
}
9

В этом случае, если вы действительно хотите использовать метод ReadToEnd в MemoryStream с помощью простого способа, вы можете использовать этот метод расширения для этого:

public static class SetExtensions
{
    public static string ReadToEnd(this MemoryStream BASE)
    {
        BASE.Position = 0;
        StreamReader R = new StreamReader(BASE);
        return R.ReadToEnd();
    }
}

И вы можете использовать этот метод следующим образом:

using (MemoryStream m = new MemoryStream())
{
    //for example i want to serialize an object into MemoryStream
    //I want to use XmlSeralizer
    XmlSerializer xs = new XmlSerializer(_yourVariable.GetType());
    xs.Serialize(m, _yourVariable);

    //the easy way to use ReadToEnd method in MemoryStream
    MessageBox.Show(m.ReadToEnd());
}
6
byte[] array = Encoding.ASCII.GetBytes("MyTest1 - MyTest2");
MemoryStream streamItem = new MemoryStream(array);

// convert to string
StreamReader reader = new StreamReader(streamItem);
string text = reader.ReadToEnd();
5

Почему бы не сделать хороший метод расширения для типа MemoryStream?

public static class MemoryStreamExtensions
{

    static object streamLock = new object();

    public static void WriteLine(this MemoryStream stream, string text, bool flush)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text + Environment.NewLine);
        lock (streamLock)
        {
            stream.Write(bytes, 0, bytes.Length);
            if (flush)
            {
                stream.Flush();
            }
        }
    }

    public static void WriteLine(this MemoryStream stream, string formatString, bool flush, params string[] strings)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(String.Format(formatString, strings) + Environment.NewLine);
        lock (streamLock)
        {
            stream.Write(bytes, 0, bytes.Length);
            if (flush)
            {
                stream.Flush();
            }
        }
    }

    public static void WriteToConsole(this MemoryStream stream)
    {
        lock (streamLock)
        {
            long temporary = stream.Position;
            stream.Position = 0;
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true))
            {
                string text = reader.ReadToEnd();
                if (!String.IsNullOrEmpty(text))
                {
                    Console.WriteLine(text);
                }
            }
            stream.Position = temporary;
        }
    }
}

Конечно, будьте осторожны при использовании этих методов в сочетании со стандартными.:)... вам нужно будет использовать этот удобный streamLock, если вы это сделаете, для concurrency.

5

Немного измененная версия ответа Брайана позволяет факультативно управлять началом чтения. Это, пожалуй, самый простой способ. вероятно, не самый эффективный, но понятный и понятный.

Public Function ReadAll(ByVal memStream As MemoryStream, Optional ByVal startPos As Integer = 0) As String
    ' reset the stream or we'll get an empty string returned
    ' remember the position so we can restore it later
    Dim Pos = memStream.Position
    memStream.Position = startPos

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' reset the position so that subsequent writes are correct
    memStream.Position = Pos

    Return str
End Function
  • 3
    это действительно не добавляет ничего нового в ответ Брайана

Ещё вопросы

Сообщество Overcoder
Наверх
Меню