2012-09-09 11 views
7

Sto tentando di aggiungere alcuni dati a uno stream. Funziona bene con FileStream, ma non per MemoryStream a causa della dimensione del buffer fisso.Aggiunta a MemoryStream

Il metodo che scrive i dati nel flusso è separato dal metodo che crea il flusso (l'ho semplificato notevolmente nell'esempio seguente). Il metodo che crea lo stream non conosce la lunghezza dei dati da scrivere nello stream.

public void Foo(){ 
    byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo"); 
    Stream s1 = new FileStream("someFile.txt", FileMode.Append, FileAccess.Write, FileShare.Read); 
    s1.Write(existingData, 0, existingData.Length); 


    Stream s2 = new MemoryStream(existingData, 0, existingData.Length, true); 
    s2.Seek(0, SeekOrigin.End); //move to end of the stream for appending 

    WriteUnknownDataToStream(s1); 
    WriteUnknownDataToStream(s2); // NotSupportedException is thrown as the MemoryStream is not expandable 
} 

public static void WriteUnknownDataToStream(Stream s) 
{ 
    // this is some example data for this SO query - the real data is generated elsewhere and is of a variable, and often large, size. 
    byte[] newBytesToWrite = System.Text.Encoding.UTF8.GetBytes("bar"); // the length of this is not known before the stream is created. 
    s.Write(newBytesToWrite, 0, newBytesToWrite.Length); 
} 

Un idea che avevo era quella di inviare una espandibile MemoryStream alla funzione, quindi aggiungere i dati restituiti ai dati esistenti.

public void ModifiedFoo() 
{ 
    byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo"); 
    Stream s2 = new MemoryStream(); // expandable capacity memory stream 

    WriteUnknownDataToStream(s2); 

    // append the data which has been written into s2 to the existingData 
    byte[] buffer = new byte[existingData.Length + s2.Length]; 
    Buffer.BlockCopy(existingData, 0, buffer, 0, existingData.Length); 
    Stream merger = new MemoryStream(buffer, true); 
    merger.Seek(existingData.Length, SeekOrigin.Begin); 
    s2.CopyTo(merger); 
} 

Soluzioni migliori (più efficienti)?

+3

Puoi spiegare perché non stai utilizzando un flusso espandibile per entrambe le scritture? – Rotem

+1

ah, così? Stream s2 = new MemoryStream(); // stream di memoria a capacità espandibile s2.Write (existingData, 0, existingData.Length); WriteUnknownDataToStream (s2); –

+0

Sì, questo è ciò che intendo ... ecco perché è uno stream e non un array, no? – Rotem

risposta

25

Una possibile soluzione non è limitare la capacità dello MemoryStream in primo luogo. Se non si conosce in anticipo il numero totale di byte che sarà necessario scrivere, creare un MemoryStream con capacità non specificata e utilizzarlo per entrambe le scritture.

byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo"); 
MemoryStream ms = new MemoryStream(); 
ms.Write(existingData, 0, existingData.Length); 
WriteUnknownData(ms); 

Questo sarà senza dubbio meno performante di inizializzazione di un MemoryStream da un byte[], ma se avete bisogno di continuare a scrivere al flusso credo che sia l'unica opzione.

+1

Se la differenza di prestazioni è importante, è possibile [specificare la capacità iniziale dello stream] (http://msdn.microsoft.com/en-us/library/bx3c0489.aspx). In questo modo, se si indovina (o si conosce) la dimensione finale, non ci saranno riallocazioni. Se si indovina male, si sprecherà memoria o si avranno riallocazioni che influiscono sulle prestazioni, ma funzionerà comunque. – svick