Wie lässt sich der Inhalt eines Streams am besten in einen anderen kopieren? Gibt es eine Standardmethode für diese Aufgabe?
Antworten
Zu viele Anzeigen?Ab .NET 4.5 gibt es die Stream.CopyToAsync
Methode
input.CopyToAsync(output);
Dies führt zu einer Task
die nach der Fertigstellung fortgesetzt werden können, etwa so:
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
Beachten Sie, dass je nachdem, wo der Aufruf von CopyToAsync
ausgeführt wird, kann der nachfolgende Code auf demselben Thread fortgesetzt werden, der ihn aufgerufen hat, oder auch nicht.
El SynchronizationContext
die beim Aufruf von await
bestimmt, in welchem Thread die Fortsetzung ausgeführt wird.
Außerdem führt dieser Aufruf (und dies ist ein Implementierungsdetail, das sich noch ändern kann) immer noch Lese- und Schreibvorgänge durch (es wird nur kein Thread verschwendet, der auf den Abschluss der E/A blockiert).
Ab .NET 4.0 gibt es die Funktion Stream.CopyTo
Methode
input.CopyTo(output);
Für .NET 3.5 und früher
Das Framework bietet hierfür keine Hilfestellung; Sie müssen den Inhalt manuell kopieren, etwa so:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write (buffer, 0, read);
}
}
Hinweis 1: Diese Methode ermöglicht es Ihnen, den Fortschritt zu melden (x bisher gelesene Bytes ...)
Anmerkung 2: Warum eine feste Puffergröße verwenden und nicht input.Length
? Denn diese Länge ist möglicherweise nicht verfügbar! Von der docs :
Wenn eine von Stream abgeleitete Klasse das Suchen nicht unterstützt, lösen Aufrufe von Length, SetLength, Position und Seek eine NotSupportedException aus.
Ich verwende die folgenden Erweiterungsmethoden. Sie haben optimierte Überladungen für den Fall, dass ein Stream ein MemoryStream ist.
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);
}
NET Framework 4 führt die neue Methode "CopyTo" der Stream-Klasse des System.IO-Namensraums ein. Mit dieser Methode können wir einen Stream in einen anderen Stream einer anderen Stream-Klasse kopieren.
Hier ein 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/>");
Es gibt tatsächlich eine weniger schwerfällige Methode, eine Stream-Kopie zu erstellen. Beachten Sie jedoch, dass dies voraussetzt, dass Sie die gesamte Datei im Speicher ablegen können. Versuchen Sie dies nicht, wenn Sie mit Dateien arbeiten, die Hunderte von Megabyte oder mehr groß sind, und seien Sie vorsichtig.
public static void CopySmallTextStream(Stream input, Stream output)
{
using (StreamReader reader = new StreamReader(input))
using (StreamWriter writer = new StreamWriter(output))
{
writer.Write(reader.ReadToEnd());
}
}
HINWEIS: Es kann auch einige Probleme mit Binärdaten und Zeichenkodierungen geben.
- See previous answers
- Weitere Antworten anzeigen