Comment lire exactement n octets à partir d’un stream?

C’est un peu plus délicat que ce que j’avais imaginé au départ. J’essaie de lire n octets à partir d’un stream.

MSDN affirme que Read n’a pas à renvoyer n octets, il doit simplement renvoyer au moins 1 octets et au maximum n octets, 0 octet étant le cas particulier d’atteindre la fin du stream.

En général, j’utilise quelque chose comme

var buf = new byte[size]; var count = stream.Read (buf, 0, size); if (count != size) { buf = buf.Take (count).ToArray (); } yield return buf; 

J’espère avoir exactement la size octets, mais selon les spécifications, FileStream serait également autorisé à renvoyer un grand nombre de morceaux d’un octet. Cela doit être évité.

Une façon de résoudre ce problème serait de disposer de 2 mémoires tampons, une pour la lecture et une pour la collecte des morceaux jusqu’à l’obtention du nombre d’octets demandé. C’est un peu lourd cependant.

J’ai aussi jeté un coup d’œil à BinaryReader mais ses spécifications n’indiquent pas clairement que n octets seront retournés à coup sûr.

Pour clarifier: bien sûr, à la fin du stream, le nombre d’octets renvoyés peut être inférieur à la size – ce n’est pas un problème. Je parle seulement de ne pas recevoir n octets même s’ils sont disponibles dans le stream.

Une version légèrement plus lisible:

 int offset = 0; while (offset < count) { int read = stream.Read(buffer, offset, count - offset); if (read == 0) throw new System.IO.EndOfStreamException(); offset += read; } 

Ou écrit en tant que méthode d'extension pour la classe Stream :

 public static class StreamUtils { public static byte[] ReadExactly(this System.IO.Stream stream, int count) { byte[] buffer = new byte[count]; int offset = 0; while (offset < count) { int read = stream.Read(buffer, offset, count - offset); if (read == 0) throw new System.IO.EndOfStreamException(); offset += read; } System.Diagnostics.Debug.Assert(offset == count); return buffer; } } 

Simplement; vous faites une boucle;

 int read, offset = 0; while(leftToRead > 0 && (read = stream.Read(buf, offset, leftToRead)) > 0) { leftToRead -= read; offset += read; } if(leftToRead > 0) throw new EndOfStreamException(); // not enough! 

Après cela, buf aurait dû être rempli avec exactement la bonne quantité de données du stream, ou aurait jeté un EOF.