Stream in Byte-Array verwandeln: Ein Leitfaden für C#-Entwickler (2025 Edition)
\n\nHaben Sie sich jemals dabei ertappt: „Warum, C#, gibst du mir nicht einfach die Möglichkeit, diesen Stream mit einer einzigen Zeile in ein Byte-Array zu verwandeln?“. Wenn ja, sind Sie nicht allein. Die Frage „Creating a byte array from a stream“ auf Stack Overflow sammelt tausende Aufrufe, und das nicht ohne Grund. Die Aufgabe scheint elementar, aber der Teufel steckt, wie immer, im Detail: Leistung, Speicher, Asynchronität und .NET-Versionen.
Im Jahr 2025 bietet uns das .NET-Ökosystem mehrere elegante Lösungen. In diesem Artikel analysieren wir 5 Best Practices – von Klassikern bis hin zu Neuheiten. Sie erfahren, wann Sie MemoryStream verwenden, warum BinaryReader immer noch relevant ist und wie Sie Ihre Anwendung bei der Arbeit mit riesigen Streams nicht zum Absturz bringen. Los geht's!
1. Der Klassiker: MemoryStream und CopyTo
\n\nDie beliebteste und intuitivste Methode. Wenn Sie einen Stream haben (z. B. aus einer Datei, einem Netzwerk oder dem Arbeitsspeicher), „gießen“ Sie ihn einfach in einen MemoryStream und rufen dann ToArray() auf.
public static byte[] StreamToBytesUsingMemoryStream(Stream inputStream)\n{\n using (var memoryStream = new MemoryStream())\n {\n inputStream.CopyTo(memoryStream);\n return memoryStream.ToArray();\n }\n}\n\nVorteile:
\n- \n
- Einfachheit und Lesbarkeit. \n
- Funktioniert in allen .NET-Versionen (Framework, Core, 5+). \n
- Unterstützt
CopyToAsyncfür asynchrone Arbeit. \n
Nachteile:
\n- \n
- Wenn der Stream riesig ist (z. B. 1 GB), halten Sie die Daten doppelt im Speicher: zuerst im
MemoryStream, dann im Array. \n - Nicht die schnellste Option für sehr kleine Streams (Overhead durch Objekterstellung). \n
Wann verwenden: Für mittelgroße Streams (bis zu 100 MB) und wenn die Lesbarkeit des Codes wichtiger ist als Mikrooptimierungen.
\n\n2. Der asynchrone Held: ReadAsync und Buffer
\n\nIn der modernen Entwicklung ist Asynchronität der Standard. Die Methode ReadAsync ermöglicht es, Daten portionsweise zu lesen, ohne den Thread zu blockieren. Dies ist besonders nützlich in ASP.NET Core oder GUI-Anwendungen.
public static async Task<byte[]> StreamToBytesAsync(Stream inputStream)\n{\n using (var memoryStream = new MemoryStream())\n {\n byte[] buffer = new byte[8192]; // 8 KB – Standardgröße\n int bytesRead;\n while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0)\n {\n await memoryStream.WriteAsync(buffer, 0, bytesRead);\n }\n return memoryStream.ToArray();\n }\n}\n\nProfessioneller Tipp: Die Puffergröße kann geändert werden. Für Netzwerk-Streams sind 8 KB der goldene Mittelweg. Für SSD-Festplatten kann sie auf 64 KB erhöht werden.
\n\nVorteile:
\n- \n
- Blockiert den aufrufenden Thread nicht. \n
- Ermöglicht die Verarbeitung von Daten „on the fly“ (z. B. Berechnung eines Hashs). \n
- Kontrolle über den Speicherverbrauch. \n
Nachteile:
\n- \n
- Etwas mehr Code. \n
- Erfordert Verständnis des async/await-Musters. \n
3. BinaryReader: Ein alter Freund ist besser als zwei neue
\n\nViele vergessen BinaryReader, zu Unrecht. Er kann den gesamten Stream mit einem einzigen Befehl lesen – ReadBytes. Aber es gibt einen Haken: Er muss die Länge des Streams im Voraus kennen.
public static byte[] StreamToBytesUsingBinaryReader(Stream inputStream)\n{\n if (inputStream.CanSeek)\n {\n inputStream.Position = 0; // Zurücksetzen der Position, falls nötig\n using (var reader = new BinaryReader(inputStream, Encoding.UTF8, leaveOpen: true))\n {\n return reader.ReadBytes((int)inputStream.Length);\n }\n }\n else\n {\n throw new InvalidOperationException("Stream unterstützt keine Positionierung (Seeking).");\n }\n}