Vraag Een bytearray maken vanuit een stream


Wat is de voorkeursmethode voor het maken van een bytearray van een invoerstroom?

Hier is mijn huidige oplossing met .NET 3.5.

Stream s;
byte[] b;

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

Is het nog steeds een beter idee om brokken van de stream te lezen en te schrijven?


725
2017-10-21 13:42


oorsprong


antwoorden:


Het hangt er echt van af of je kunt vertrouwen s.Length. Voor veel streams weet u gewoon niet hoeveel gegevens er zullen zijn. In dergelijke gevallen - en daarvoor. NET 4 - zou ik code als volgt gebruiken:

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();
    }
}

Met .NET 4 en hoger zou ik gebruiken Stream.CopyTo, wat in principe hetzelfde is als de lus in mijn code - maak de MemoryStream, bel stream.CopyTo(ms) en dan terugkeren ms.ToArray(). Klus geklaard.

Ik moet misschien uitleggen waarom mijn antwoord langer is dan de andere. Stream.Read garandeert niet dat het alles zal lezen waar om gevraagd wordt. Als u bijvoorbeeld vanuit een netwerkstream leest, kan deze de waarde van één pakket lezen en vervolgens terugkeren, zelfs als er binnenkort meer gegevens beschikbaar zijn. BinaryReader.Read blijft doorgaan tot het einde van de stream of je opgegeven grootte, maar je moet nog steeds de grootte weten.

De bovenstaande methode blijft lezen (en kopiëren naar een MemoryStream) totdat de gegevens opraken. Vervolgens vraagt ​​het de MemoryStream om een ​​kopie van de gegevens in een array terug te sturen. Als u de maat weet om mee te beginnen - of denken je kent de maat, zonder dat je het zeker weet - je kunt de MemoryStream eerst zo groot maken dat hij zo groot is. Op dezelfde manier kunt u aan het einde een vinkje plaatsen en als de lengte van de stream dezelfde grootte heeft als de buffer (geretourneerd door MemoryStream.GetBuffer) dan kun je de buffer gewoon retourneren. Dus de bovenstaande code is niet helemaal geoptimaliseerd, maar zal op zijn minst correct zijn. Het neemt geen enkele verantwoordelijkheid voor het sluiten van de stream - de beller zou dat moeten doen.

Zien Dit artikel voor meer info (en een alternatieve implementatie).


1064
2017-10-21 13:45



Terwijl het antwoord van Jon juist is, herschrijft hij code die al in CopyTo bestaat. Dus voor .Net 4 gebruikt de Sandip-oplossing, maar voor de vorige versie van .Net gebruikt Jon het antwoord. De code van Sandip zou verbeterd kunnen worden door "gebruik" te gebruiken, aangezien uitzonderingen in CopyTo in veel situaties waarschijnlijk zijn en de MemoryStream niet verwijderd zouden laten.

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

585
2017-07-05 16:45



Ik wil er alleen op wijzen dat als je een MemoryStream hebt die je al hebt memorystream.ToArray() daarom.

Ook als je te maken hebt met streams met onbekende of verschillende subtypen en je kunt een MemoryStream, je kunt die methode doorgeven voor die gevallen en toch het geaccepteerde antwoord voor de anderen gebruiken, zoals dit:

public static byte[] StreamToByteArray(Stream stream)
{
    if (stream is MemoryStream)
    {
        return ((MemoryStream)stream).ToArray();                
    }
    else
    {
        // Jon Skeet's accepted answer 
        return ReadFully(stream);
    }
}

88
2018-04-13 14:54



MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();

58
2018-02-12 13:33



gewoon mijn paar centen ... de praktijk die ik vaak gebruik, is om de methoden als deze te organiseren als een aangepaste helper

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

voeg naamruimte toe aan het configuratiebestand en gebruik het waar u maar wilt


45
2018-02-18 16:01



Je kunt het zelfs mooier maken met extensies:

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();
                }
            }
        }
    }
}

En noem het dan een gewone methode:

byte[] arr = someStream.ToByteArray()

9
2017-07-18 17:01



Ik krijg een compileerfout met de code van Bob (de code van de vrager). Stream.Length is lang, terwijl BinaryReader.ReadBytes een integer-parameter gebruikt. In mijn geval verwacht ik niet te maken te hebben met streams die groot genoeg zijn om een ​​lange precisie te vereisen, dus gebruik ik het volgende:

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);
}

8
2018-05-31 00:55