2008-09-16 13 views
442

Se mi viene fornito un MemoryStream che so è stato popolato con un String, come si ottiene un String indietro?Come si ottiene una stringa da un MemoryStream?

+1

mai sicuro se reader.close è sempre necessario. Ho avuto problemi in passato, quindi di regola faccio sempre solo il lato sicuro. – Crusty

risposta

411

Questo esempio mostra come leggere e scrivere una stringa in un 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 
+3

Non ha intenzione di disporre di StreamWriter quando il la funzione va oltre lo scopo comunque? –

+12

Dispose non viene chiamato quando una variabile esce dall'ambito. Finalize verrà chiamato quando il GC si avvicina, ma Dispose è qualcosa che deve essere chiamato prima che la variabile vada fuori dal campo di applicazione. Non lo chiamo sopra perché so che l'implementazione di StreamWriter e StreamReader non richiede la chiamata di Dispose, ma passa semplicemente la chiamata al flusso sottostante. Tuttavia, un argomento legittimo può essere fatto per chiamare Dipose per tutto ciò che implementa IDisposable poiché non si può garantire che una futura release non richieda la sua eliminazione. – Brian

+11

@MichaelEakins Perché la risposta dovrebbe essere anche in C#, quando la domanda è contrassegnata come VB.Net? –

32

utilizzare un StreamReader, quindi è possibile utilizzare il metodo ReadToEnd che restituisce una stringa.

+10

Voglio solo dire che il 'Basestream' dovrebbe aver impostato la sua posizione su 0. Come' memoryStream.Position = 0; '. –

96

Utilizzo di uno StreamReader per convertire MemoryStream in una stringa.

<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

L'impostazione di Posizione a 0 limita la capacità di riutilizzo del metodo: è meglio consentire al chiamante di gestirlo. Cosa succede se il flusso contiene dati prima della stringa, che il chiamante sa come gestire? –

+1

L'istruzione using assicurerà che lo StreamReader venga eliminato, ma la documentazione dice che StreamReader chiude il flusso sottostante quando viene eliminato. Pertanto, il metodo chiude il MemoryStream che viene passato, il che è concettualmente non cool per i chiamanti anche se dubito che MemoryStream.Dispose faccia molto. – Trillian

+0

Sei corretto. In genere è una cattiva idea utilizzare il metodo Dispose nelle classi helper dello stream, specialmente se il flusso viene passato in un metodo come parametro. Aggiornerò questa risposta Ho anche una risposta più completa di seguito. – Brian

231

È inoltre possibile utilizzare

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

io non credo che questo è meno efficiente, ma non riuscivo a giurarlo. Permette anche di scegliere una codifica diversa, mentre usando uno StreamReader dovresti specificarlo come parametro.

+19

+1: perfetto per scopi di test unitario, grazie. – rsenna

+6

La codifica è nello spazio dei nomi System.Text – northben

+1

Stavo cercando l'equivalente PowerShell di questo e ho dovuto usare questo. ([System.Text.Encoding] :: ASCII) .GetString (ms.ToArray()) – Lewis

5

Una versione leggermente modificata della risposta di Brian consente la gestione opzionale di avvio lettura, questo sembra essere il metodo più semplice. probabilmente non il più efficiente, ma facile da capire e da usare.

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

in realtà non aggiunge nulla di nuovo a Brian risposta –

17

soluzioni precedenti non avrebbero funzionato nei casi in cui è coinvolta la codifica. Ecco - una sorta di "vita reale" - ad esempio come fare questo correttamente ...

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

thx, stavo cercando quello scenario particolare :) –

10

In questo caso, se si vuole veramente utilizzare ReadToEnd metodo MemoryStream un modo semplice, è possibile utilizzare questo metodo di estensione per raggiungere questo obiettivo:

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

ed è possibile utilizzare questo metodo in questo modo:

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

Perché non fare un bel metodo di estensione del tipo 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; 
     } 
    } 
} 

Naturalmente, fare attenzione quando si utilizzano questi metodi in combinazione con quelli standard. :) ... dovrai usare quel comodo streamLock se lo fai, per la concorrenza.

10

Questo esempio mostra come leggere una stringa da un MemoryStream, in cui ho utilizzato una serializzazione (utilizzando DataContractJsonSerializer), passare la stringa da qualche server al client e quindi, come recuperare il MemoryStream dalla stringa passata come parametro, quindi, deserializzare il MemoryStream.

Ho utilizzato parti di diversi post per eseguire questo esempio.

Spero che questo aiuti.

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 
    } 
} 
8
byte[] array = Encoding.ASCII.GetBytes("MyTest1 - MyTest2"); 
MemoryStream streamItem = new MemoryStream(array); 

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