2009-12-10 16 views
554

Ho bisogno di scrivere un test unitario per un metodo che prende uno stream che proviene da un file di testo. Vorrei fare fare qualcosa di simile:Come posso generare uno stream da una stringa?

Stream s = GenerateStreamFromString("a,b \n c,d"); 

risposta

702
public static Stream GenerateStreamFromString(string s) 
{ 
    var stream = new MemoryStream(); 
    var writer = new StreamWriter(stream); 
    writer.Write(s); 
    writer.Flush(); 
    stream.Position = 0; 
    return stream; 
} 

Non dimenticare di utilizzare Usando:

using (var stream = GenerateStreamFromString("a,b \n c,d")) 
{ 
    // ... Do stuff to stream 
} 

Chi l'StreamWriter non in via di dismissione. StreamWriter è solo un wrapper attorno al flusso di base e non utilizza alcuna risorsa che deve essere smaltita. Il metodo Dispose chiuderà il sottostante Stream a cui sta scrivendo StreamWriter. In questo caso è lo MemoryStream che vogliamo restituire.

In .NET 4.5 c'è ora un sovraccarico per StreamWriter che mantiene aperto il flusso sottostante dopo che il writer è stato eliminato, ma questo codice fa la stessa cosa e funziona anche con altre versioni di .NET.

Vedi Is there any way to close a StreamWriter without closing its BaseStream?

+98

Un importante concetto di punto da sottolineare è che uno stream è composto da byte, mentre una stringa è composta da caratteri. È fondamentale capire che convertendo un carattere in uno o più byte (o in un flusso come in questo caso) __always__ utilizza (o assume) una particolare codifica. Questa risposta, sebbene corretta in alcuni casi, utilizza la codifica predefinita e potrebbe non essere adatta in generale. Passare esplicitamente una codifica al costruttore StreamWriter renderebbe più evidente che l'autore deve considerare le implicazioni di Codifica. – ricovox

+2

Si dice "Non dimenticare di usare l'uso" per utilizzare lo stream, ma nel metodo 'GenerateStreamFromString' non si sta utilizzando l'uso con StreamWriter. C'è una ragione per questo? – Ben

+6

@ Ben Sì. Se si smaltisce StreamWriter, anche lo streaming sottostante verrà chiuso. Non lo vogliamo. L'unico motivo per cui lo scrittore è usa e getta è quello di ripulire il flusso, quindi è sicuro da ignorare. –

20

utilizzare la classe MemoryStream, chiamando Encoding.GetBytes per trasformare il tuo stringa in un array di byte prima.

Successivamente è necessario un TextReader nello stream? In tal caso, è possibile fornire direttamente un StringReader e ignorare i passaggi MemoryStream e Encoding.

9

Qui si va:

private Stream GenerateStreamFromString(String p) 
{ 
    Byte[] bytes = UTF8Encoding.GetBytes(p); 
    MemoryStream strm = new MemoryStream(); 
    strm.Write(bytes, 0, bytes.Length); 
    return strm; 
} 
+1

La posizione deve essere ripristinata dopo la scrittura. Meglio usare il costruttore, come nella risposta di joelnet. –

529

Un'altra soluzione:

public static MemoryStream GenerateStreamFromString(string value) 
{ 
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? "")); 
} 
+22

Nel caso in cui qualcuno lo usi con una stringa XML deserializzazione, ho dovuto passare da UTF8 a Unicode per farlo funzionare senza una bandiera. Ottimo post !!! – Gaspa79

+1

Mi piace questo (con il tweak di Rhyous e il banale zucchero extra da usare come metodo di estensione) meglio della risposta accettata; più flessibile, meno LOC e meno oggetti coinvolti (nessuna necessità esplicita di StreamWriter) – KeithS

+0

'new MemoryStream (Encoding.UTF8.GetBytes (" \ ufeff "+ (value ??" "))' se è necessario disporre della distinta base incluso all'inizio del flusso – robert4

97

aggiungerlo a una classe di utilità stringa statica:

public static Stream ToStream(this string str) 
{ 
    MemoryStream stream = new MemoryStream(); 
    StreamWriter writer = new StreamWriter(stream); 
    writer.Write(str); 
    writer.Flush(); 
    stream.Position = 0; 
    return stream; 
} 

Questo aggiunge una funzione di estensione in modo da poter semplicemente:

using (var stringStream = "My string".ToStream()) 
{ 
    // use stringStream 
} 
+2

Ho scoperto che il flusso restituito viene chiuso (causando eccezioni semi-casuali) quando il garbage collector pulisce il 'StreamWriter'. La correzione consisteva nell'usare un costruttore diverso - uno che mi permettesse di specificare ** leaveOpen **. – Bevan

-1
/// <summary> 
/// Get Byte[] from String 
/// </summary> 
/// <param name="str"></param> 
/// <returns></returns> 
public static byte[] GetBytes(string str) 
{ 
    byte[] bytes = new byte[str.Length * sizeof(char)]; 
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); 
    return bytes; 
} 

/// <summary> 
/// Get Stream from String 
/// </summary> 
/// <param name="str"></param> 
/// <returns></returns> 
public static Stream GetStream(string str) 
{ 
    return new MemoryStream(GetBytes(str)); 
} 
+2

System.String is away UTF-16 .Se 'vero? – abatishchev

+3

Tu dici" Non ha bisogno di conoscere la codifica String per funzionare. "È come dire che non importa di che colore è la tua auto perché stai per scaricare la vernice verde dappertutto. out, si sta usando in modo sconosciuto la codifica UTF-16 per convertire la stringa in byte. Diciamo che ora si scrive il contenuto di questo Stream in un file e lo si apre come un file di testo. Vedrai spazi tra ogni personaggio. – ricovox

-1

Una buona combinazione di estensioni String:

public static byte[] GetBytes(this string str) 
{ 
    byte[] bytes = new byte[str.Length * sizeof(char)]; 
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); 
    return bytes; 
} 

public static Stream ToStream(this string str) 
{ 
    Stream StringStream = new MemoryStream(); 
    StringStream.Read(str.GetBytes(), 0, str.Length); 
    return StringStream; 
} 
33
public Stream GenerateStreamFromString(string s) 
{ 
    return new MemoryStream(Encoding.UTF8.GetBytes(s)); 
} 
8

ho usato un mix di risposte in questo modo:

public static Stream ToStream(this string str, Encoding enc = null) 
{ 
    enc = enc ?? Encoding.UTF8; 
    return new MemoryStream(enc.GetBytes(str ?? "")); 
} 

E poi usare in questo modo:

String someStr="This is a Test"; 
Encoding enc = getEncodingFromSomeWhere(); 
using (Stream stream = someStr.ToStream(enc)) 
{ 
    // Do something with the stream.... 
} 
+0

Thomas, perché giù voto? enc = enc ?? Encoding.UTF8 mi consente di chiedere specificamente stream con codifica specifica, o un valore predefinito di UTF8, e poiché in .net (fino a quando lo uso .net 4.0) non puoi dare un tipo di riferimento diverso da string un valore predefinito in funzione firma questa linea è necessaria, ha senso? – Robocide

+0

menzionare che è necessario metterlo in una classe separata (classe statica non generica?) È anche utile e ridurre i voti bassi. – Ali

4

Utilizziamo i metodi di estensione elencati di seguito. Penso che dovresti fare in modo che lo sviluppatore prenda una decisione sulla codifica, quindi c'è meno magia coinvolta.

public static class StringExtensions { 

    public static Stream ToStream(this string s) { 
     return s.ToStream(Encoding.UTF8); 
    } 

    public static Stream ToStream(this string s, Encoding encoding) { 
     return new MemoryStream(encoding.GetBytes(s ?? "")); 
    } 
} 
+0

Preferirei implementare il primo metodo come 'return ToStream (s, Encoding.UTF8);'. Nell'implementazione corrente ('return s.ToStream (Encoding.UTF8);', lo sviluppatore è costretto a pensare più duramente per comprendere il codice e sembra che il caso di 's == null' non sia gestito e genera' NullReferenceException'. – Palec

0

Versione leggermente modificata dei metodi di estensione suggeriti in un commento della risposta di @ JoelNet e della risposta di @Shaun Bowe. Perché sono d'accordo con il commento di @ Palec.

public static Stream ToStream(this string value) => ToStream(value, Encoding.UTF8); 

public static Stream ToStream(this string value, Encoding encoding) => new MemoryStream(encoding.GetBytes(value ?? string.Empty)); 
Problemi correlati