Tworzenie tablicy bajtów ze strumienia

Jaka jest preferowana metoda tworzenia tablicy bajtów ze strumienia wejściowego?

Oto moje obecne rozwiązanie z. NET 3.5.

Stream s;
byte[] b;

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

Czy nadal lepszym pomysłem jest odczytywanie i zapisywanie fragmentów strumienia?

Author: huysentruitw, 2008-10-21

16 answers

To naprawdę zależy od tego, czy można zaufać s.Length. W przypadku wielu strumieni po prostu nie wiesz, ile będzie danych. W takich przypadkach - i przed. NET 4-użyłbym kodu w ten sposób:

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

Z. NET 4 i wyżej, użyłbym Stream.CopyTo, co w zasadzie odpowiada pętli w moim kodzie-Utwórz MemoryStream, wywołaj stream.CopyTo(ms), a następnie zwróć ms.ToArray(). Zrobione.

Powinienem być może wyjaśnić, dlaczego moja odpowiedź jest dłuższa niż inne. Stream.Read nie gwarantuje, że przeczyta wszystko, o co prosi. Na przykład, jeśli czytasz ze strumienia sieciowego, może on odczytać wartość jednego pakietu, a następnie powrócić, nawet jeśli wkrótce pojawi się więcej danych. BinaryReader.Read będzie kontynuować aż do końca strumienia lub określonego rozmiaru, ale nadal musisz znać rozmiar, aby rozpocząć.

Powyższa metoda będzie czytać (i kopiować do MemoryStream) dopóki nie zabraknie danych. Następnie zwraca MemoryStream kopię danych w tablicy. Jeśli wiesz rozmiar na początek - lub pomyśl znasz rozmiar, nie będąc pewnym - możesz skonstruować MemoryStream, aby był tym rozmiarem na początek. Podobnie można umieścić sprawdzenie na końcu, i jeśli długość strumienia jest tego samego rozmiaru co bufor (zwracany przez MemoryStream.GetBuffer) wtedy możesz po prostu zwrócić bufor. Tak więc powyższy kod nie jest do końca zoptymalizowany, ale przynajmniej będzie poprawny. Nie ponosi żadnej odpowiedzialności za zamknięcie strumienia - rozmówca powinien to zrobić.

Zobacz ten artykuł aby uzyskać więcej informacji (i alternatywną implementację).

 1342
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-06 12:36:37

Chociaż odpowiedź Jona jest poprawna, przepisuje kod, który już istnieje w CopyTo. Tak więc dla. Net 4 Użyj rozwiązania Sandip, ale dla poprzedniej wersji. Net użyj odpowiedzi Jona. Kod sandipa zostałby ulepszony przez użycie "using", ponieważ wyjątki w CopyTo są, w wielu sytuacjach, całkiem prawdopodobne i pozostawiłyby MemoryStream nie usunięte.

public static byte[] ReadFully(Stream input)
{
    using (MemoryStream ms = new MemoryStream())
    {
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
 776
Author: Nathan Phillips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-24 13:34:10

Chcę tylko zaznaczyć, że w przypadku, gdy masz MemoryStream, masz już memorystream.ToArray() do tego.

Ponadto, jeśli masz do czynienia ze strumieniami nieznanych lub różnych podtypów i możesz otrzymać MemoryStream, możesz przekazać tę metodę dla tych przypadków i nadal używać zaakceptowanej odpowiedzi dla innych, jak to:

public static byte[] StreamToByteArray(Stream stream)
{
    if (stream is MemoryStream)
    {
        return ((MemoryStream)stream).ToArray();                
    }
    else
    {
        // Jon Skeet's accepted answer 
        return ReadFully(stream);
    }
}
 120
Author: Fernando Neira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-25 15:34:05
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
 70
Author: Sandip Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-12 13:33:29

Tylko moje grosze... praktyka, której często używam, polega na organizowaniu takich metod jako niestandardowego pomocnika

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

Dodaj przestrzeń nazw do pliku konfiguracyjnego i używaj jej w dowolnym miejscu

 54
Author: Mr. Pumpkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-18 16:01:22

Możesz po prostu użyć metody ToArray () klasy MemoryStream, dla ex-

MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = ms.ToArray();
 20
Author: Nilesh Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-24 19:39:01

Możesz nawet uczynić go bardziej fantazyjnym z rozszerzeniami:

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

A następnie wywołaj ją jako zwykłą metodę:

byte[] arr = someStream.ToByteArray()
 11
Author: Michal T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 13:05:52

Dostaję błąd czasu kompilacji z kodem Boba (tj. pytającego). Strumień.Length is a long while BinaryReader.ReadBytes pobiera parametr integer. W moim przypadku nie spodziewam się, że będę miał do czynienia z strumieniami na tyle dużymi, aby wymagały długiej precyzji, więc używam następującego:

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
Author: Brian Hinchey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 00:55:31

Jeśli komuś się spodoba, oto jedyne rozwiązanie. NET 4+ utworzone jako metoda rozszerzenia bez niepotrzebnego wywoływania Dispose na MemoryStream. Jest to beznadziejnie trywialna optymalizacja, ale warto zauważyć, że nie pozbycie się MemoryStream nie jest prawdziwą porażką.

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        var ms = new MemoryStream();
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
 6
Author: SensorSmith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-17 22:57:13

Ta powyżej jest ok...ale napotkasz uszkodzenie danych, gdy wysyłasz rzeczy przez SMTP (jeśli zajdzie taka potrzeba). Zmieniłem na coś innego, co pomoże poprawnie wysłać bajt za bajt: '

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;
        }'
 4
Author: NothinRandom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-30 22:22:24

W przestrzeni nazw RestSharp.Rozszerzenia istnieje metoda ReadAsBytes. Wewnątrz tej metody jest używany MemoryStream i tam jest ten sam kod jak w niektórych przykładach na tej stronie, ale gdy używasz RestSharp jest to najprostszy sposób.

using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
 4
Author: Wieslaw Olborski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-14 15:31:19

Utwórz klasę pomocniczą i odwołaj się do niej gdziekolwiek chcesz jej użyć.

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}
 3
Author: Kalyn Padayachee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 13:45:47

Jest to funkcja, której używam, testowałem i dobrze pracowałem. proszę pamiętać, że 'input' nie powinno być null i ' input.pozycja 'powinna zresetować się do' 0 ' przed odczytaniem, w przeciwnym razie złamie pętlę odczytu i nic nie zostanie odczytane, aby przekonwertować do tablicy.

    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;
        }
    }
 3
Author: Fred.S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-10 02:47:26

Możesz użyć tej metody rozszerzenia.

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();
    }
}
 2
Author: Egemen Çiftci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-27 06:49:07
public static byte[] ToByteArray(Stream stream)
    {
        if (stream is MemoryStream)
        {
            return ((MemoryStream)stream).ToArray();
        }
        else
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }            
    }
 -1
Author: önder çalbay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-17 13:42:28

Udało mi się to zrobić na jednej linii:

byte [] byteArr= ((MemoryStream)localStream).ToArray();

Jak wyjaśniono przez johnnyRose , powyższy kod będzie działał tylko dla MemoryStream

 -5
Author: Abba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24