75 votes

Un moyen élégant de consommer (tous les octets d'un) BinaryReader ?

Existe-t-il un moyen élégant d'émuler le StreamReader.ReadToEnd méthode avec BinaryReader ? Peut-être faut-il mettre tous les octets dans un tableau d'octets ?

Je fais ça :

read1.ReadBytes((int)read1.BaseStream.Length);

...mais il doit y avoir un meilleur moyen.

2 votes

Je pense qu'après tout, c'est le moyen le plus élégant.

107voto

Scott Rippey Points 6921

Réponse originale (lire la mise à jour ci-dessous !)

Il suffit de le faire :

byte[] allData = read1.ReadBytes(int.MaxValue);

El documentation dit qu'il va lire tous les octets jusqu'à ce que la fin du flux soit atteinte.


Mise à jour

Bien que cela semble élégant, et que la documentation semble indiquer que cela fonctionnerait, la réalité est la suivante mise en œuvre (vérifié dans .NET 2, 3.5 et 4) alloue un tableau d'octets de taille complète pour les données, ce qui causera probablement un problème d'erreur d'affichage. OutOfMemoryException sur un système 32 bits.

Par conséquent, je dirais qu'en fait il n'y a pas de moyen élégant .

Au lieu de cela, je recommanderais la variante suivante de la réponse d'@iano. Cette variante ne repose pas sur .NET 4 :
Créer une méthode d'extension pour BinaryReader (ou Stream le code est le même pour les deux).

public static byte[] ReadAllBytes(this BinaryReader reader)
{
    const int bufferSize = 4096;
    using (var ms = new MemoryStream())
    {
        byte[] buffer = new byte[bufferSize];
        int count;
        while ((count = reader.Read(buffer, 0, buffer.Length)) != 0)
            ms.Write(buffer, 0, count);
        return ms.ToArray();
    }

}

12 votes

Cela me donne une exception OutOfMemoryException dans .NET 4.0 (test avec LINQPad). En effet, la décompilation du source avec Reflector révèle que ReadBytes tente d'allouer un tableau d'octets de la taille du nombre donné : byte[] buffer = new byte[count] ;.

1 votes

@iano Vous avez raison. J'ai également décompilé .NET 2.0, et c'est la même chose. Je vais mettre à jour ma réponse avec un avertissement.

0 votes

Quelqu'un peut-il m'expliquer pourquoi buffer = new byte[count] provoque une exception outofmemory ? J'aimerais comprendre les principes fondamentaux de la mise en mémoire tampon et savoir pourquoi elle est nécessaire. Merci

80voto

iano Points 782

Il n'y a pas de facile moyen de le faire avec BinaryReader. Si vous ne connaissez pas à l'avance le nombre de caractères que vous devez lire, il est préférable d'utiliser MemoryStream :

public byte[] ReadAllBytes(Stream stream)
{
    using (var ms = new MemoryStream())
    {
        stream.CopyTo(ms);
        return ms.ToArray();
    }
}

Pour éviter la copie supplémentaire lors de l'appel ToArray() vous pourriez plutôt renvoyer le Position et tampon, via GetBuffer() .

0 votes

Je suis d'accord, c'est probablement la réponse la plus élégante. A noter, cependant, Stream.CopyTo n'est disponible qu'en .NET 4.

0 votes

+1. Je suis tombée sur cette réponse en cherchant une solution à mes maux. J'avais un problème avec une classe dans un assemblage tiers (dont je voulais récupérer tous les octets) qui dérivait de Stream mais son Length était toujours nulle. J'ai d'abord essayé une approche basée sur une méthode d'extension, mais je l'ai trouvée peu maniable.

2 votes

J'ajouterais stream.Position = 0 ; avant CopyTo

4voto

Seraphim's Points 2393

Pour copier le contenu d'un flux vers un autre, j'ai résolu de lire "quelques" octets jusqu'à ce que la fin du fichier soit atteinte :

private const int READ_BUFFER_SIZE = 1024;
using (BinaryReader reader = new BinaryReader(responseStream))
{
    using (BinaryWriter writer = new BinaryWriter(File.Open(localPath, FileMode.Create)))
    {
        int byteRead = 0;
        do
        {
            byte[] buffer = reader.ReadBytes(READ_BUFFER_SIZE);
            byteRead = buffer.Length;
            writer.Write(buffer);
            byteTransfered += byteRead;
        } while (byteRead == READ_BUFFER_SIZE);                        
    }                
}

1voto

Omer Hijazi Points 65

J'ai eu le même problème.
Tout d'abord, obtenez la taille du fichier en utilisant FileInfo.Length.
Ensuite, créez un tableau d'octets et définissez sa valeur à BinaryReader.ReadBytes(FileInfo.Length). Par exemple

var size = new FileInfo(yourImagePath).Length;
byte[] allBytes = yourReader.ReadBytes(System.Convert.ToInt32(size));

0voto

MarqueIV Points 4268

J'utilise ceci, qui utilise le sous-jacent BaseStream pour vous donner les informations de longueur dont vous avez besoin. Cela permet de garder les choses simples et agréables.

Vous trouverez ci-dessous trois méthodes d'extension sur BinaryReader :

  • La première lit depuis la position actuelle du flux jusqu'à la fin.
  • La seconde lit l'ensemble du flux en une seule fois
  • Le troisième utilise le Range pour spécifier le sous-ensemble de données qui vous intéresse.

    public static class BinaryReaderExtensions {

    public static byte[] ReadBytesToEnd(this BinaryReader binaryReader) {
    
        var length = binaryReader.BaseStream.Length - binaryReader.BaseStream.Position;
        return binaryReader.ReadBytes((int)length);
    }
    
    public static byte[] ReadAllBytes(this BinaryReader binaryReader) {
    
        binaryReader.BaseStream.Position = 0;
        return binaryReader.ReadBytes((int)binaryReader.BaseStream.Length);
    }
    
    public static byte[] ReadBytes(this BinaryReader binaryReader, Range range) {
    
        var (offset, length) = range.GetOffsetAndLength((int)binaryReader.BaseStream.Length);
        binaryReader.BaseStream.Position = offset;
        return binaryReader.ReadBytes(length);      
    }

    }

Leur utilisation est alors triviale et claire...

// 1 - Reads everything in as a byte array
var rawBytes = myBinaryReader.ReadAllBytes();

// 2 - Reads a string, then reads the remaining data as a byte array
var someString = myBinaryReader.ReadString();
var rawBytes = myBinaryReader.ReadBytesToEnd();

// 3 - Uses a range to read the last 44 bytes
var rawBytes = myBinaryReader.ReadBytes(^44..);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X