Bagaimana Anda mendapatkan string dari MemoryStream?

532

Jika saya diberi kartu MemoryStreamyang saya tahu telah diisi dengan String, bagaimana cara mendapatkan Stringkembali?

Brian
sumber
1
Tidak pernah yakin apakah reader.close selalu diperlukan. Saya memiliki masalah di masa lalu sehingga sebagai aturan saya selalu lakukan hanya untuk berada di sisi yang aman.
Crusty

Jawaban:

468

Sampel ini menunjukkan cara membaca dan menulis string ke MemoryStream.


Imports System.IO

Module Module1
  Sub Main()
    ' We don't need to dispose any of the MemoryStream 
    ' because it is a managed object. However, just for 
    ' good practice, we'll close the MemoryStream.
    Using ms As New MemoryStream
      Dim sw As 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
      '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
      Dim sr As New StreamReader(ms)
      Dim myStr = sr.ReadToEnd()
      Console.WriteLine(myStr)

      ' We can dispose our StreamWriter and StreamReader 
      ' now, though this isn't necessary (they don't hold 
      ' any resources open on their own).
      sw.Dispose()
      sr.Dispose()
    End Using

    Console.WriteLine("Press any key to continue.")
    Console.ReadKey()
  End Sub
End Module
Brian
sumber
3
Bukankah itu akan membuang StreamWriter ketika fungsi itu keluar dari ruang lingkup?
Tim Keating
14
Buang tidak dipanggil saat variabel keluar dari ruang lingkup. Finalisasi akan dipanggil ketika GC menyiasatinya, tetapi Buang adalah sesuatu yang harus dipanggil sebelum variabel keluar dari ruang lingkup. Saya tidak menyebutnya di atas karena saya tahu implementasi StreamWriter dan StreamReader tidak memerlukan Buang untuk dipanggil, itu hanya meneruskan panggilan ke aliran yang mendasarinya. Namun, argumen yang sah dapat dibuat untuk memanggil Dipose untuk apa pun yang menerapkan IDisposable karena Anda tidak dapat menjamin rilis di masa mendatang tidak akan mengharuskannya untuk dibuang.
Brian
12
@MichaelEakins Mengapa jawabannya bahkan dalam C #, ketika pertanyaannya ditandai sebagai VB.Net?
Rowland Shaw
1
Saya senang mengetahui tentang "pembantu" yang menyampaikan panggilan pembuangan ke aliran yang mendasarinya, tetapi ini sepertinya keputusan desain yang buruk.
Gerard ONeill
2
Keputusan ini kemudian dikurangi: msdn.microsoft.com/en-us/library/…
Mark Sowul
310

Anda juga bisa menggunakan

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

Saya tidak berpikir ini kurang efisien, tetapi saya tidak bisa bersumpah untuk itu. Ini juga memungkinkan Anda memilih penyandian yang berbeda, sedangkan menggunakan StreamReader Anda harus menentukan itu sebagai parameter.

Pembuat kode
sumber
6
Pengkodean ada dalam System.Text namespace
northben
2
Saya mencari PowerShell yang setara dengan ini dan harus menggunakan ini. ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray ())
Lewis
Solusi ini bermanfaat karena dapat digunakan setelah MemoryStream ditutup.
Jacob Horbulyk
2
FWIW, saya menemukan ini tidak bekerja dengan string yang sangat besar, saya mendapatkan OutOfMemoryExceptions. Menggunakan StreamReaderbukan memecahkan masalah.
Grant H.
Karena ini bisa menjadi jebakan: Ini tidak menyadari tanda urutan byte dan mungkin menyertakan Hex 00di awal string. 00 3C 3F-> .<?di Hex Editor tapi di VS atau Notepad ++: <?. Jadi Anda tidak dapat melihat perbedaannya bahkan jika Anda membandingkan string dengan mata, hanya alat perbandingan atau editor Hex yang akan menunjukkan perbedaannya. Jika Anda masih menggunakannya, pikirkan String.TrimStart. Lihat: docs.microsoft.com/en-us/dotnet/api/…
Skalli
99

Menggunakan StreamReader untuk mengubah MemoryStream menjadi sebuah String.

<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
Brian
sumber
3
Mengatur Posisi ke 0 membatasi kemampuan reuse dari metode - yang terbaik adalah membiarkan penelepon mengatur ini. Bagaimana jika aliran berisi data sebelum string, bahwa pemanggil tahu bagaimana menangani?
Alex Lyman
1
Pernyataan menggunakan akan memastikan bahwa StreamReader Anda dibuang, tetapi dokumentasi mengatakan bahwa StreamReader menutup aliran yang mendasarinya ketika itu dibuang. Oleh karena itu, metode Anda menutup MemoryStream yang dilewati, yang secara konsep tidak keren untuk penelepon bahkan jika saya ragu MemoryStream.
Trillian
Anda benar. Biasanya merupakan ide yang buruk untuk menggunakan metode Buang di kelas pembantu aliran, terutama jika aliran dilewatkan ke metode sebagai parameter. Saya akan memperbarui jawaban ini. Saya juga punya jawaban yang lebih lengkap di bawah ini.
Brian
Jika Anda mendekompilasi kelas-kelas itu, Anda akan melihat bahwa metode buang cukup memanggil Buang () pada aliran apa pun yang tidak nol dalam contoh (TextWriter, MemoryStream, dll)
Sinaesthetic
39

menggunakan StreamReader , maka Anda bisa menggunakan metode ReadToEnd yang mengembalikan string.

Darren Kopp
sumber
12
Saya hanya ingin menyebutkan, bahwa Basestreamseharusnya telah menetapkan Posisinya ke 0. Suka memoryStream.Position = 0;.
Aykut Çevik
26
byte[] array = Encoding.ASCII.GetBytes("MyTest1 - MyTest2");
MemoryStream streamItem = new MemoryStream(array);

// convert to string
StreamReader reader = new StreamReader(streamItem);
string text = reader.ReadToEnd();
Sadjad Khazaie
sumber
22

Solusi sebelumnya tidak akan berfungsi dalam kasus di mana penyandian terlibat. Inilah - semacam "kehidupan nyata" - contoh bagaimana melakukan ini dengan benar ...

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()));
}
Arek Bal
sumber
15

Dalam hal ini, jika Anda benar-benar ingin menggunakan ReadToEndmetode MemoryStreamdengan cara yang mudah, Anda dapat menggunakan Metode Ekstensi ini untuk mencapai ini:

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

Dan Anda dapat menggunakan metode ini dengan cara ini:

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());
}
Mehdi Khademloo
sumber
11

Sampel ini menunjukkan cara membaca string dari MemoryStream, di mana saya telah menggunakan serialisasi (menggunakan DataContractJsonSerializer), meneruskan string dari beberapa server ke klien, dan kemudian, bagaimana memulihkan MemoryStream dari string yang dikirimkan sebagai parameter, kemudian , deserialize the MemoryStream.

Saya telah menggunakan bagian dari posting yang berbeda untuk melakukan sampel ini.

Semoga ini bisa membantu.

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
    }
}
Sebastian Ferrari
sumber
5

Versi yang sedikit dimodifikasi dari jawaban Brian memungkinkan manajemen opsional mulai membaca, Ini tampaknya menjadi metode termudah. mungkin bukan yang paling efisien, tetapi mudah dimengerti dan digunakan.

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
James
sumber
3
itu benar-benar menambahkan tidak ada yang baru untuk jawaban Brian
Luis Filipe
5

Mengapa tidak membuat metode ekstensi yang bagus pada tipe 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;
        }
    }
}

Tentu saja, berhati-hatilah saat menggunakan metode ini bersamaan dengan yang standar. :) ... Anda harus menggunakan streamLock yang praktis jika Anda melakukannya, untuk konkurensi.

Alexandru
sumber
0

Saya perlu mengintegrasikan dengan kelas yang membutuhkan Stream untuk Menulis di atasnya:

XmlSchema schema;
// ... Use "schema" ...

var ret = "";

using (var ms = new MemoryStream())
{
    schema.Write(ms);
    ret = Encoding.ASCII.GetString(ms.ToArray());
}
//here you can use "ret"
// 6 Lines of code

Saya membuat kelas sederhana yang dapat membantu mengurangi baris kode untuk penggunaan banyak:

public static class MemoryStreamStringWrapper
{
    public static string Write(Action<MemoryStream> action)
    {
        var ret = "";
        using (var ms = new MemoryStream())
        {
            action(ms);
            ret = Encoding.ASCII.GetString(ms.ToArray());
        }

        return ret;
    }
}

maka Anda dapat mengganti sampel dengan satu baris kode

var ret = MemoryStreamStringWrapper.Write(schema.Write);
Riccardo Bassilichi
sumber