Frage

Was ist der beste Weg, um den Inhalt von einem Stream in einen anderen zu kopieren? Gibt es ein Standardhilfsmethode für das?

War es hilfreich?

Lösung

Von .NET 4.5 auf, besteht die Task dass kann auf fortgesetzt werden, wenn sie abgeschlossen sind, etwa so:

await input.CopyToAsync(output)

// Code from here on will be run in a continuation.

Beachten Sie, dass je nachdem, wo der Anruf an CopyToAsync gemacht wird, dass der Code folgt oder nicht auf dem gleichen Thread fortsetzen kann, die es genannt.

Die SynchronizationContext , die erfasst wurde beim Aufruf von < a href = "http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx" rel = "noreferrer"> await die Fortsetzung ausgeführt wird auf wird feststellen, welche fädeln.

Darüber hinaus dieser Aufruf (und dies ist eine Implementierung Detail Änderungen vorbehalten) noch Sequenzen lesen und schreiben (es verschwendet nicht nur ein Gewinde an I / O-Abschluss Blockierung).

Von .NET 4.0 auf, es ist die docs :

  

Wenn eine Klasse von Stream-abgeleitete nicht der Suche nach Unterstützung, ruft Länge, SetLength, Position, und sucht eine NotSupportedException werfen.

Andere Tipps

Memory hat .WriteTo (outStream);

und .NET 4.0 hat .CopyTo auf normalen Stream-Objekt.

.NET 4.0:

instream.CopyTo(outstream);

Ich verwende die folgenden Erweiterungsmethoden. Sie haben optimieren Überlastungen für, wenn ein Strom ist ein Memorystream.

    public static void CopyTo(this Stream src, Stream dest)
    {
        int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
        byte[] buffer = new byte[size];
        int n;
        do
        {
            n = src.Read(buffer, 0, buffer.Length);
            dest.Write(buffer, 0, n);
        } while (n != 0);           
    }

    public static void CopyTo(this MemoryStream src, Stream dest)
    {
        dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
    }

    public static void CopyTo(this Stream src, MemoryStream dest)
    {
        if (src.CanSeek)
        {
            int pos = (int)dest.Position;
            int length = (int)(src.Length - src.Position) + pos;
            dest.SetLength(length); 

            while(pos < length)                
                pos += src.Read(dest.GetBuffer(), pos, length - pos);
        }
        else
            src.CopyTo((Stream)dest);
    }

Die grundlegenden Fragen, die Implementierungen von "CopyStream" unterscheiden sind:

  • Größe des Lesepuffers
  • Größe der Schreibvorgänge
  • Können wir mehr als ein Thread (Schreiben, während wir lesen).

Die Antworten auf diese Fragen ergeben sich sehr unterschiedliche Implementierungen von CopyStream in und sind davon abhängig, welche Art von Streams, die Sie haben und was Sie versuchen, zu optimieren. Die „beste“ Implementierung würde sogar müssen wissen, welche spezielle Hardware die Ströme wurden Lesen und Schreiben zu.

Es gibt tatsächlich eine weniger plumpe Art und Weise einen Strom Kopie zu tun. Nehmen Sie jedoch beachten, dass dies bedeutet, dass Sie die gesamte Datei im Speicher speichern kann. Versuchen Sie nicht, und diese zu verwenden, wenn Sie mit Dateien arbeiten, die in die Hunderte von Megabytes gehen oder mehr, ohne Vorsicht.

public static void CopyStream(Stream input, Stream output)
{
  using (StreamReader reader = new StreamReader(input))
  using (StreamWriter writer = new StreamWriter(output))
  {
    writer.Write(reader.ReadToEnd());
  }
}

. Hinweis: Es gibt auch einige Fragen im Zusammenhang mit binären Daten und Zeichencodierungen sein kann

.NET Framework 4 neue "CopyTo" Methode der Stream-Klasse System.IO-Namespace einzuführen. Mit dieser Methode können wir einen Strom in einem anderen Strom von verschiedener Stream-Klasse kopieren.

Hier ist Beispiel dafür.

    FileStream objFileStream = File.Open(Server.MapPath("TextFile.txt"), FileMode.Open);
    Response.Write(string.Format("FileStream Content length: {0}", objFileStream.Length.ToString()));

    MemoryStream objMemoryStream = new MemoryStream();

    // Copy File Stream to Memory Stream using CopyTo method
    objFileStream.CopyTo(objMemoryStream);
    Response.Write("<br/><br/>");
    Response.Write(string.Format("MemoryStream Content length: {0}", objMemoryStream.Length.ToString()));
    Response.Write("<br/><br/>");

Leider gibt es keine wirklich einfache Lösung. Sie können so etwas versuchen:

Stream s1, s2;
byte[] buffer = new byte[4096];
int bytesRead = 0;
while (bytesRead = s1.Read(buffer, 0, buffer.Length) > 0) s2.Write(buffer, 0, bytesRead);
s1.Close(); s2.Close();

Aber das Problem mit, dass die unterschiedliche Umsetzung der Stream-Klasse anders verhalten könnte, wenn es nichts zu lesen. Ein Strom, eine Datei von einer lokalen Festplatte zu lesen wird wahrscheinlich blockieren, bis die Lese operaition genug Daten von der Platte zu füllen die Puffer und nur zurückgeben weniger Daten gelesen hat, wenn er das Ende der Datei erreicht. Auf der anderen Seite wird ein Strom aus dem Netz lesen kann weniger Daten zurück, obwohl es mehr Daten empfangen gelassen werden.

Sie immer die Dokumentation der spezifischen Stream-Klasse überprüfen Sie, bevor Sie eine generische Lösung verwenden.

Es kann ein Weg sein, diese effizienter zu machen, je nachdem, welche Art von Strom mit dem Sie arbeiten. Wenn Sie eine oder beide Ihrer Ströme zu einem Memorystream umwandeln können, können Sie die GetBuffer Methode verwenden, um direkt mit einem Byte-Array zu arbeiten, um Ihre Daten darstellen. Auf diese Weise können Sie verwenden Methoden wie Array.CopyTo, die alle abstrahieren die Probleme von fryguybob angehoben. Sie können nur .NET vertrauen den optimalen Weg zu wissen, um die Daten zu kopieren.

, wenn Sie einen procdure einen Stream auf andere zu kopieren, die eine, die nick geschrieben ist gut, aber es fehlt die Position zurückgesetzt, sollte es sein

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[32768];
    long TempPos = input.Position;
    while (true)    
    {
        int read = input.Read (buffer, 0, buffer.Length);
        if (read <= 0)
            return;
        output.Write (buffer, 0, read);
    }
    input.Position = TempPos;// or you make Position = 0 to set it at the start
}

, aber wenn es in der Laufzeit nicht unter Verwendung eines Verfahrens ist shpuld Sie Speicher-Stream verwenden

Stream output = new MemoryStream();
byte[] buffer = new byte[32768]; // or you specify the size you want of your buffer
long TempPos = input.Position;
while (true)    
{
    int read = input.Read (buffer, 0, buffer.Length);
    if (read <= 0)
        return;
    output.Write (buffer, 0, read);
 }
    input.Position = TempPos;// or you make Position = 0 to set it at the start

Da keine der Antworten abgedeckt haben eine asynchrone Art und Weise des Kopierens von einem Strom zum anderen, hier ist ein Muster, das ich erfolgreich in einer Port-Forwarding-Anwendung verwendet haben, Daten von einem Netzwerk Stream in einen anderen zu kopieren. Es fehlt die Ausnahmebehandlung, das Muster zu betonen.

const int BUFFER_SIZE = 4096;

static byte[] bufferForRead = new byte[BUFFER_SIZE];
static byte[] bufferForWrite = new byte[BUFFER_SIZE];

static Stream sourceStream = new MemoryStream();
static Stream destinationStream = new MemoryStream();

static void Main(string[] args)
{
    // Initial read from source stream
    sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}

private static void BeginReadCallback(IAsyncResult asyncRes)
{
    // Finish reading from source stream
    int bytesRead = sourceStream.EndRead(asyncRes);
    // Make a copy of the buffer as we'll start another read immediately
    Array.Copy(bufferForRead, 0, bufferForWrite, 0, bytesRead);
    // Write copied buffer to destination stream
    destinationStream.BeginWrite(bufferForWrite, 0, bytesRead, BeginWriteCallback, null);
    // Start the next read (looks like async recursion I guess)
    sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}

private static void BeginWriteCallback(IAsyncResult asyncRes)
{
    // Finish writing to destination stream
    destinationStream.EndWrite(asyncRes);
}

Für .NET 3.5 und vor try:

MemoryStream1.WriteTo(MemoryStream2);

Einfach und sicher - stellen neuen Strom von der ursprünglichen Quelle:

    MemoryStream source = new MemoryStream(byteArray);
    MemoryStream copy = new MemoryStream(byteArray);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top