web-dev-qa-db-de.com

Erstellen eines Byte-Arrays aus einem Stream

Was ist die bevorzugte Methode zum Erstellen eines Bytearrays aus einem Eingabestrom? 

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, Brocken des Streams zu lesen und zu schreiben?

789
Bob

Es hängt wirklich davon ab, ob Sie s.Length vertrauen können oder nicht. Bei vielen Streams wissen Sie einfach nicht, wie viele Daten es gibt. In solchen Fällen - und vor .NET 4 - würde ich Code wie folgt verwenden:

public static byte[] ReadFully(Stream input)
{
    byte[] buffer = new byte[16*1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}

Bei .NET 4 und höher würde ich Stream.CopyTo verwenden, was im Wesentlichen der Schleife in meinem Code entspricht. Erstellen Sie die MemoryStream, rufen Sie stream.CopyTo(ms) auf und geben Sie dann ms.ToArray() zurück. Job erledigt.

Ich sollte vielleicht erklären, warum meine Antwort länger ist als die anderen. Stream.Read garantiert nicht, dass alles gelesen wird, wonach es gefragt wird. Wenn Sie beispielsweise aus einem Netzwerkstrom lesen, kann er den Wert eines Pakets lesen und dann zurückkehren, auch wenn bald mehr Daten vorhanden sind. BinaryReader.Read wird bis zum Ende des Streams oder der angegebenen Größe fortgesetzt, Sie müssen jedoch zunächst die Größe kennen.

Die obige Methode liest (und kopiert in eine MemoryStream), bis die Daten ausgehen. Anschließend fordert die Variable MemoryStream auf, eine Kopie der Daten in einem Array zurückzugeben. Wenn Sie die Größe kennen, mit der Sie beginnen möchten - oder think, kennen Sie die Größe, ohne sich zu vergewissern, dass Sie die Variable MemoryStream so definieren können, dass sie mit dieser Größe beginnt. Ebenso können Sie am Ende einen Haken setzen, und wenn die Länge des Streams dieselbe Größe wie der Puffer hat (von MemoryStream.GetBuffer zurückgegeben), 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.

In diesem Artikel finden Sie weitere Informationen (und eine alternative Implementierung).

1153
Jon Skeet

Während Jons Antwort korrekt ist, schreibt er Code, der bereits in CopyTo vorhanden ist, neu. Verwenden Sie für .Net 4 die Lösung von Sandip, aber für die vorherige Version von .Net verwenden Sie die Antwort von Jon. Sandips Code würde durch die Verwendung von "using" verbessert, da Ausnahmen in CopyTo in vielen Situationen sehr wahrscheinlich sind und die MemoryStream nicht verworfen lassen würden.

public static byte[] ReadFully(Stream input)
{
    using (MemoryStream ms = new MemoryStream())
    {
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
631
Nathan Phillips

Ich möchte nur darauf hinweisen, dass Sie für den Fall, dass Sie einen MemoryStream haben, bereits memorystream.ToArray() haben. 

Wenn Sie sich mit Streams unbekannter oder verschiedener Subtypen befassen und Sie eine MemoryStream erhalten können, können Sie diese Methode für diese Fälle weiterleiten und trotzdem die akzeptierte Antwort für die anderen verwenden:

public static byte[] StreamToByteArray(Stream stream)
{
    if (stream is MemoryStream)
    {
        return ((MemoryStream)stream).ToArray();                
    }
    else
    {
        // Jon Skeet's accepted answer 
        return ReadFully(stream);
    }
}
95
Fernando Neira
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
59
Sandip Patel

nur meine paar Cent ... die Praxis, die ich oft verwende, ist die Organisation der Methoden als benutzerdefinierte Helfer

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}

fügen Sie der Konfigurationsdatei einen Namespace hinzu und verwenden Sie ihn an beliebiger Stelle

46
Mr. Pumpkin

Mit Erweiterungen können Sie es sogar noch schicker machen:

namespace Foo
{
    public static class Extensions
    {
        public static byte[] ToByteArray(this Stream stream)
        {
            using (stream)
            {
                using (MemoryStream memStream = new MemoryStream())
                {
                     stream.CopyTo(memStream);
                     return memStream.ToArray();
                }
            }
        }
    }
}

Und dann rufen Sie es als normale Methode auf:

byte[] arr = someStream.ToByteArray()
11
Michal T

Sie können einfach die ToArray () - Methode der MemoryStream-Klasse verwenden, z.

MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = ms.ToArray();
8
Nilesh Kumar

Ich bekomme einen Fehler bei der Kompilierung mit Bob's Code (d. H. Dem Fragesteller). Stream.Length ist lang, wohingegen BinaryReader.ReadBytes einen ganzzahligen Parameter verwendet. In meinem Fall erwarte ich nicht, dass ich mit Streams zu tun habe, die groß genug sind, um lange Präzision zu erfordern.

Stream s;
byte[] b;

if (s.Length > int.MaxValue) {
  throw new Exception("This stream is larger than the conversion algorithm can currently handle.");
}

using (var br = new BinaryReader(s)) {
  b = br.ReadBytes((int)s.Length);
}
7
Brian Hinchey

Die obige ist in Ordnung ... aber beim Senden von Daten über SMTP werden Daten beschädigt (falls erforderlich). Ich habe etwas anderes geändert, das hilft, Byte für Byte korrekt zu senden: '

using System;
using System.IO;

        private static byte[] ReadFully(string input)
        {
            FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer
            BinaryReader binReader = new BinaryReader(sourceFile);
            byte[] output = new byte[sourceFile.Length]; //create byte array of size file
            for (long i = 0; i < sourceFile.Length; i++)
                output[i] = binReader.ReadByte(); //read until done
            sourceFile.Close(); //dispose streamer
            binReader.Close(); //dispose reader
            return output;
        }'
3
NothinRandom

Erstellen Sie eine Hilfsklasse, und referenzieren Sie sie an einer beliebigen Stelle, an der Sie sie verwenden möchten. 

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}
2

Falls es jemandem gefällt, handelt es sich hier um eine nur .NET 4+ -Lösung, die als Erweiterungsmethode ohne den unnötigen Dispose-Aufruf des MemoryStream erstellt wurde. Dies ist eine hoffnungslos triviale Optimierung, aber es ist erwähnenswert, dass das Versäumnis, einen MemoryStream zu entsorgen, kein echter Fehlschlag ist.

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        var ms = new MemoryStream();
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
1
SensorSmith

Sie können diese Erweiterungsmethode verwenden.

public static class StreamExtensions
{
    public static byte[] ToByteArray(this Stream stream)
    {
        var bytes = new List<byte>();

        int b;
        while ((b = stream.ReadByte()) != -1)
            bytes.Add((byte)b);

        return bytes.ToArray();
    }
}
0
Tempeck

Im Namespace RestSharp.Extensions gibt es die Methode ReadAsBytes. In dieser Methode wird MemoryStream verwendet. Es gibt den gleichen Code wie in einigen Beispielen auf dieser Seite. Wenn Sie RestSharp verwenden, ist dies jedoch der einfachste Weg.

using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
0

Dies ist die Funktion, die ich verwende, getestet und gut gearbeitet 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 wird gelesen, um in ein Array zu konvertieren.

    public static byte[] StreamToByteArray(Stream input)
    {
        if (input == null)
            return null;
        byte[] buffer = new byte[16 * 1024];
        input.Position = 0;
        using (MemoryStream ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            byte[] temp = ms.ToArray();

            return temp;
        }
    }
0
Fred.S