Was ist die bevorzugte Methode zum Erstellen eines Byte-Arrays aus einem Eingabestream?
Hier ist meine aktuelle Lösung mit .NET 3.5.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
Ist es immer noch eine bessere Idee, Teile des Streams zu lesen und zu schreiben?
c#
.net-3.5
inputstream
Bob
quelle
quelle
Antworten:
Es hängt wirklich davon ab, ob Sie vertrauen können oder nicht
s.Length
. Bei vielen Streams wissen Sie einfach nicht, wie viele Daten vorhanden sein werden. In solchen Fällen - und vor .NET 4 - würde ich folgenden Code verwenden:Mit .NET 4 und höher würde ich verwenden
Stream.CopyTo
, was im Grunde der Schleife in meinem Code entspricht - erstellen Sie denMemoryStream
, rufen Sie aufstream.CopyTo(ms)
und kehren Sie dann zurückms.ToArray()
. Job erledigt.Ich sollte vielleicht erklären, warum meine Antwort länger ist als die der anderen.
Stream.Read
garantiert nicht, dass es alles liest, wonach es gefragt wird. Wenn Sie beispielsweise aus einem Netzwerk-Stream lesen, liest dieser möglicherweise den Wert eines Pakets und kehrt dann zurück, selbst wenn bald weitere Daten vorliegen.BinaryReader.Read
wird bis zum Ende des Streams oder Ihrer angegebenen Größe fortgesetzt, aber Sie müssen zunächst noch die Größe kennen.Bei der obigen Methode wird so lange gelesen (und in a kopiert
MemoryStream
), bis keine Daten mehr vorhanden sind. Anschließend wird der BenutzerMemoryStream
aufgefordert, eine Kopie der Daten in einem Array zurückzugeben. Wenn Sie zunächst die Größe kennen - oder glauben , die Größe zu kennen, ohne sich sicher zu sein -, können Sie die Größe zunächst so konstruierenMemoryStream
, dass sie diese Größe hat. Ebenso können Sie am Ende ein Häkchen setzen. Wenn die Länge des Streams der Größe des Puffers entspricht (zurückgegeben vonMemoryStream.GetBuffer
), können Sie den Puffer einfach zurückgeben. Der obige Code ist also nicht ganz optimiert, wird aber zumindest korrekt sein. Es übernimmt keine Verantwortung für das Schließen des Streams - der Anrufer sollte dies tun.Weitere Informationen (und eine alternative Implementierung) finden Sie in diesem Artikel .
quelle
16*1024
speziell?Während Jons Antwort richtig ist, schreibt er Code neu, der bereits in vorhanden ist
CopyTo
. Verwenden Sie für .Net 4 die Sandip-Lösung, für die vorherige Version von .Net jedoch Jons Antwort. Sandips Code würde durch die Verwendung von "using" verbessert, da AusnahmenCopyTo
in vielen Situationen sehr wahrscheinlich sind und dasMemoryStream
nicht entsorgt werden würden.quelle
input
bereits einMemorySteam
Kurzschluss vorliegt. Ich weiß, es wäre dumm von dem Anrufer, einMemoryStream
aber ...MemoryStream
dann , ob die Optimierung Sinn in Ihrem Kontext macht , ist der Vergleich der Zeit, um Millionen von Typkonvertierungen gegen die Zeit zu tun genommen , die eine kopieren , die eine istMemoryStream
in ein andererMemoryStream
.Ich möchte nur darauf hinweisen, dass Sie für den Fall, dass Sie einen MemoryStream haben, bereits einen haben
memorystream.ToArray()
.Wenn Sie es mit Streams unbekannter oder unterschiedlicher Subtypen zu tun haben und eine erhalten können
MemoryStream
, können Sie diese Methode für diese Fälle weiterleiten und die akzeptierte Antwort für die anderen weiterhin wie folgt verwenden:quelle
MemoryStream
s sind. Natürlich ist das Beispiel auch offensichtlich unvollständig, da es eine nicht initialisierte Variable verwendet.stream.Seek(1L, SeekOrigin.Begin)
, bevor Sie lesbar aufrufen , erhalten Sie, wenn der Stream ein Speicher-Stream ist, 1 Byte mehr als wenn es sich um einen anderen Stream handelt. Wenn der Anrufer erwartet, von der aktuellen Position bis zum Ende des Streams zu lesen, dürfen SieCopyTo
oder nicht verwendenToArray()
. In den meisten Fällen ist dies kein Problem, aber wenn der Anrufer nichts über dieses eigenartige Verhalten weiß, werden sie verwirrt.quelle
nur meine paar Cent ... die Praxis, die ich oft benutze, besteht darin, die Methoden wie diese als benutzerdefinierten Helfer zu organisieren
Fügen Sie der Konfigurationsdatei einen Namespace hinzu und verwenden Sie ihn an einer beliebigen Stelle
quelle
CopyTo
esStream
erst ab 4.0 verfügbar war.Sie können einfach die ToArray () -Methode der MemoryStream-Klasse verwenden, z.
quelle
Mit Erweiterungen können Sie es sogar noch schicker machen:
Und nennen Sie es dann als reguläre Methode:
quelle
Ich erhalte einen Fehler bei der Kompilierung mit dem Code von Bob (dh dem des Fragestellers). Stream.Length ist lang, während BinaryReader.ReadBytes einen ganzzahligen Parameter verwendet. In meinem Fall erwarte ich nicht, dass es sich um Streams handelt, die groß genug sind, um eine lange Genauigkeit zu erfordern. Daher verwende ich Folgendes:
quelle
Falls es jemandem gefällt, finden Sie hier eine .NET 4+ -Lösung, die als Erweiterungsmethode ohne den unnötigen Dispose-Aufruf im MemoryStream erstellt wurde. Dies ist eine hoffnungslos triviale Optimierung, aber es ist erwähnenswert, dass das Versäumnis, einen MemoryStream zu entsorgen, kein wirklicher Fehler ist.
quelle
Das obige ist in Ordnung ... aber Sie werden auf Datenbeschädigung stoßen, wenn Sie Inhalte über SMTP senden (falls erforderlich). Ich habe etwas anderes geändert, das hilft, Byte für Byte korrekt zu senden: '
quelle
Erstellen Sie eine Hilfsklasse und verweisen Sie darauf, wo immer Sie sie verwenden möchten.
quelle
Im Namespace RestSharp.Extensions gibt es die Methode ReadAsBytes. In dieser Methode wird MemoryStream verwendet, und es gibt denselben Code wie in einigen Beispielen auf dieser Seite. Wenn Sie jedoch RestSharp verwenden, ist dies der einfachste Weg.
quelle
Sie können diese Erweiterungsmethode verwenden.
quelle
Dies ist die Funktion, die ich benutze, getestet und gut funktioniert habe. Bitte beachten Sie, dass 'input' nicht null sein sollte und 'input.position' vor dem Lesen auf '0' zurückgesetzt werden sollte, da sonst die Leseschleife unterbrochen wird und nichts gelesen wird, um in ein Array konvertiert zu werden.
quelle
quelle
Ich konnte es in einer einzigen Zeile zum Laufen bringen:
Wie von johnnyRose klargestellt, funktioniert der obige Code nur für MemoryStream
quelle
localStream
nichtMemoryStream
? Dieser Code schlägt fehl.localStream
zu einMemoryStream
, aberlocalStream
ist nicht einMemoryStream
, es wird scheitern. Dieser Code wird einwandfrei kompiliert, kann jedoch zur Laufzeit fehlschlagen, abhängig vom tatsächlichen Typ vonlocalStream
. Sie können einen Basistyp nicht immer willkürlich in einen untergeordneten Typ umwandeln. Lesen Sie hier mehr . Dies ist ein weiteres gutes Beispiel, das erklärt, warum Sie dies nicht immer tun können.