web-dev-qa-db-fra.com

Comment convertir un flux en octet [] en C #?

Existe-t-il un moyen simple ou une méthode pour convertir une Stream en un byte[] en C #?

345
pupeno

Appelle la fonction suivante comme

byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);

Une fonction:

public static byte[] ReadToEnd(System.IO.Stream stream)
    {
        long originalPosition = 0;

        if(stream.CanSeek)
        {
             originalPosition = stream.Position;
             stream.Position = 0;
        }

        try
        {
            byte[] readBuffer = new byte[4096];

            int totalBytesRead = 0;
            int bytesRead;

            while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
            {
                totalBytesRead += bytesRead;

                if (totalBytesRead == readBuffer.Length)
                {
                    int nextByte = stream.ReadByte();
                    if (nextByte != -1)
                    {
                        byte[] temp = new byte[readBuffer.Length * 2];
                        Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                        Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                        readBuffer = temp;
                        totalBytesRead++;
                    }
                }
            }

            byte[] buffer = readBuffer;
            if (readBuffer.Length != totalBytesRead)
            {
                buffer = new byte[totalBytesRead];
                Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
            }
            return buffer;
        }
        finally
        {
            if(stream.CanSeek)
            {
                 stream.Position = originalPosition; 
            }
        }
    }
147
pedrofernandes

La solution la plus courte que je connaisse:

using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}
752
James Dingle

Dans .NET Framework 4 et versions ultérieures, la classe Stream a une méthode intégrée CopyTo que vous pouvez utiliser.

Pour les versions précédentes du framework, la fonction d'aide pratique à avoir est la suivante:

public static void CopyStream(Stream input, Stream output)
{
    byte[] b = new byte[32768];
    int r;
    while ((r = input.Read(b, 0, b.Length)) > 0)
        output.Write(b, 0, r);
}

Utilisez ensuite l’une des méthodes ci-dessus pour copier sur une MemoryStream et appelez GetBuffer:

var file = new FileStream("c:\\foo.txt", FileMode.Open);

var mem = new MemoryStream();

// If using .NET 4 or later:
file.CopyTo(mem);

// Otherwise:
CopyStream(file, mem);

// getting the internal buffer (no additional copying)
byte[] buffer = mem.GetBuffer();
long length = mem.Length; // the actual length of the data 
                          // (the array may be longer)

// if you need the array to be exactly as long as the data
byte[] truncated = mem.ToArray(); // makes another copy

Edit: À l'origine, j'ai suggéré d'utiliser la réponse de Jason pour un Stream qui prend en charge la propriété Length. Mais il avait un défaut car il supposait que la Stream renverrait tout son contenu dans un seul Read, ce qui n'est pas nécessairement vrai (pas pour un Socket, par exemple.) 'sais pas s'il existe un exemple d'implémentation Stream dans la BCL qui prend en charge Length mais qui peut renvoyer les données en morceaux plus courts que ceux demandés, mais n'importe qui peut hériter de Stream this pourrait facilement être le cas.

Il est probablement plus simple d'utiliser la solution générale ci-dessus dans la plupart des cas, mais supposons que vous vouliez lire directement dans un tableau qui est bigEnough:

byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
    offset += r;

En d'autres termes, appelez à plusieurs reprises Read et déplacez la position dans laquelle vous souhaitez stocker les données.

43
Daniel Earwicker
    byte[] buf;  // byte array
    Stream stream=Page.Request.InputStream;  //initialise new stream
    buf = new byte[stream.Length];  //declare arraysize
    stream.Read(buf, 0, buf.Length); // read from stream to byte array
27
user734862

J'utilise cette classe d'extension:

public static class StreamExtensions
{
    public static byte[] ReadAllBytes(this Stream instream)
    {
        if (instream is MemoryStream)
            return ((MemoryStream) instream).ToArray();

        using (var memoryStream = new MemoryStream())
        {
            instream.CopyTo(memoryStream);
            return memoryStream.ToArray();
        }
    }
}

Copiez simplement la classe dans votre solution et vous pourrez l'utiliser sur tous les flux:

byte[] bytes = myStream.ReadAllBytes()

Fonctionne très bien pour tous mes flux et enregistre beaucoup de code! Bien sûr, vous pouvez modifier cette méthode pour utiliser certaines des autres approches afin d’améliorer les performances si nécessaire, mais j’aime rester simple.

22
JCH2k
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
18
Tavo

Ok, peut-être que quelque chose me manque, mais voici comment je le fais:

public static Byte[] ToByteArray(this Stream stream) {
    Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
    Byte[] buffer = new Byte[length];
    stream.Read(buffer, 0, length);
    return buffer;
}
6
Vinicius

si vous postez un fichier depuis un appareil mobile ou un autre

    byte[] fileData = null;
    using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
    {
        fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
    }
3
Savas Adar
Stream s;
int len = (int)s.Length;
byte[] b = new byte[len];
int pos = 0;
while((r = s.Read(b, pos, len - pos)) > 0) {
    pos += r;
}

Une solution légèrement plus compliquée est nécessaire si s.Length dépasse Int32.MaxValue. Toutefois, si vous devez lire un flux aussi volumineux en mémoire, vous pouvez envisager une approche différente de votre problème.

Edit: Si votre flux ne prend pas en charge la propriété Length, modifiez-le à l'aide d'Earwicker solution de contournement .

public static class StreamExtensions {
    // Credit to Earwicker
    public static void CopyStream(this Stream input, Stream output) {
        byte[] b = new byte[32768];
        int r;
        while ((r = input.Read(b, 0, b.Length)) > 0) {
            output.Write(b, 0, r);
        }
    }
}

[...]

Stream s;
MemoryStream ms = new MemoryStream();
s.CopyStream(ms);
byte[] b = ms.GetBuffer();
2
jason

Technique rapide et sale:

    static byte[] StreamToByteArray(Stream inputStream)
    {
        if (!inputStream.CanRead)
        {
            throw new ArgumentException(); 
        }

        // This is optional
        if (inputStream.CanSeek)
        {
            inputStream.Seek(0, SeekOrigin.Begin);
        }

        byte[] output = new byte[inputStream.Length];
        int bytesRead = inputStream.Read(output, 0, output.Length);
        Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
        return output;
    }

Tester:

    static void Main(string[] args)
    {
        byte[] data;
        string path = @"C:\Windows\System32\notepad.exe";
        using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
        {
            data = StreamToByteArray(fs);
        }

        Debug.Assert(data.Length > 0);
        Debug.Assert(new FileInfo(path).Length == data.Length); 
    }

Je voudrais demander, pourquoi voulez-vous lire un flux dans un octet [], si vous souhaitez copier le contenu d'un flux, puis-je suggérer d'utiliser MemoryStream et d'écrire votre flux d'entrée dans un flux de mémoire.

2
Phil Price

Vous pouvez également essayer de lire des parties à la fois et d’élargir le tableau d’octets renvoyé:

public byte[] StreamToByteArray(string fileName)
{
    byte[] total_stream = new byte[0];
    using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read))
    {
        byte[] stream_array = new byte[0];
        // Setup whatever read size you want (small here for testing)
        byte[] buffer = new byte[32];// * 1024];
        int read = 0;

        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            stream_array = new byte[total_stream.Length + read];
            total_stream.CopyTo(stream_array, 0);
            Array.Copy(buffer, 0, stream_array, total_stream.Length, read);
            total_stream = stream_array;
        }
    }
    return total_stream;
}
1
SwDevMan81

"bigEnough" tableau est un peu exagéré. Bien sûr, la mémoire tampon doit être "volumineuse", mais la conception correcte d'une application doit inclure des transactions et des délimiteurs. Dans cette configuration, chaque transaction aurait une longueur prédéfinie, ainsi votre tableau anticiperait un certain nombre d'octets et l'insérerait dans un tampon correctement dimensionné. Les délimiteurs assureraient l'intégrité de la transaction et seraient fournis dans chaque transaction. Pour améliorer encore votre application, vous pouvez utiliser 2 canaux (2 sockets). L’un communiquerait des transactions de messages de contrôle de longueur fixe qui incluraient des informations sur la taille et le numéro de séquence de la transaction de données à transférer par le canal de données. Le destinataire accuserait réception de la création de la mémoire tampon et les données ne seraient alors envoyées. Si vous n'avez aucun contrôle sur l'expéditeur du flux, vous avez besoin d'un tableau multidimensionnel en tant que tampon. Les matrices de composants seraient suffisamment petites pour être gérables et suffisamment grandes pour être pratiques, en fonction de votre estimation des données attendues. La logique du processus recherche les délimiteurs de début connus, puis les délimiteurs de fin dans les tableaux d'éléments suivants. Une fois que le délimiteur final est trouvé, un nouveau tampon sera créé pour stocker les données pertinentes entre les délimiteurs et le tampon initial devra être restructuré pour permettre la suppression des données.

En ce qui concerne le code pour convertir un flux en tableau d'octets, il en est un ci-dessous.

Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);
0
ArtK