Pourquoi dois-je lire le fichier pièce par pièce dans un tampon?

J’ai vu le code suivant pour obtenir le fichier dans un tableau, qui est à son tour utilisé comme paramètre pour une commande SQL l’insérant dans une colonne blob:

using (FileStream fs = new FileStream(soubor,FileMode.Open,FileAccess.Read)) int length = (int)fs.Length; buffer = new byte[length]; int count; int sum = 0; while ((count = fs.Read(buffer, sum, length - sum)) > 0) sum += count; 

Pourquoi je ne peux pas simplement faire ça:

fs.Read (tampon, 0, longueur) afin de copier simplement le contenu du fichier dans le tampon?

Merci

Il y a plus que cela “que le fichier peut ne pas tenir dans la mémoire”. Le contrat pour Stream.Read indique explicitement :

Les implémentations de cette méthode lisent un maximum d’octets de compte dans le stream actuel et les stockent dans la mémoire tampon en commençant à l’offset. La position actuelle dans le stream est avancée du nombre d’octets lus; Toutefois, si une exception se produit, la position actuelle dans le stream rest inchangée. Les implémentations renvoient le nombre d’octets lus. La valeur de retour est zéro uniquement si la position est actuellement à la fin du stream. L’implémentation sera bloquée jusqu’à ce qu’au moins un octet de données puisse être lu, dans le cas où aucune donnée n’est disponible. Read renvoie 0 uniquement lorsqu’il n’y a plus de données dans le stream et si aucune autre information n’est attendue (telle qu’un socket fermé ou une fin de fichier). Une implémentation est libre de renvoyer moins d’octets que demandé, même si la fin du stream n’a pas été atteinte.

Notez la dernière phrase – vous ne pouvez pas compter sur un seul appel à Stream.Read pour tout lire.

Les documents pour FileStream.Read ont un avertissement similaire:

Le nombre total d’octets lus dans la mémoire tampon. Cela peut être inférieur au nombre d’octets demandés si ce nombre d’octets n’est pas disponible actuellement ou à zéro si la fin du stream est atteinte.

Pour un système de fichiers local, je ne sais pas avec certitude si cela se produira réellement, mais cela pourrait fonctionner pour un fichier monté en réseau. Voulez-vous que votre application devienne fragile de cette manière?

Lire en boucle est la manière robuste de faire les choses. Personnellement, je préfère ne pas exiger que le stream prenne en charge la propriété Length , soit:

 public static byte[] ReadFully(Stream stream) { byte[] buffer = new byte[8192]; using (MemoryStream tmpStream = new MemoryStream()) { int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { tmpStream.Write(buffer, 0, bytesRead); } return tmpStream.ToArray(); } } 

C’est un peu moins efficace lorsque la longueur est connue à l’avance, mais c’est simple et agréable. Il vous suffit de l’implémenter une fois, de le placer dans une bibliothèque d’utilitaires et de l’appeler à tout moment. Si vous CanSeek vraiment la perte d’efficacité, vous pouvez utiliser CanSeek pour vérifier si la propriété Length est prise en charge et lire à plusieurs resockets dans un seul tampon dans ce cas. Soyez conscient de la possibilité que la longueur du stream puisse changer pendant que vous lisez …

Bien entendu, File.ReadAllBytes fera l’affaire encore plus simplement lorsque vous ne devez gérer qu’un fichier plutôt qu’un stream général.

Parce que votre fichier peut être très volumineux et que la mémoire tampon a généralement une taille fixe de 4 à 32 Ko. De cette façon, vous savez que vous ne remplissez pas votre mémoire de façon inconsidérée.

Bien sûr, si vous SAVEZ que la taille de votre fichier n’est pas trop grande ou si vous stockez le contenu en mémoire de toute façon, il n’ya aucune raison de ne pas tout lire en un seul coup.

Toutefois, si vous souhaitez lire le contenu de votre fichier directement dans une variable, vous n’avez pas besoin de l’API Stream. Plutôt utiliser

 File.ReadAllText(...) 

ou

 File.ReadAllBytes(...) 

Un simple fs.Read(buffer, 0, length) fonctionnera probablement, et il sera même difficile de trouver un test pour le casser. Mais ce n’est tout simplement pas garanti , et cela pourrait casser à l’avenir.

La meilleure réponse ici est d’utiliser une méthode spécialisée de la bibliothèque. Dans ce cas

 byte[] buffer = System.IO.File.ReadAllBytes(fileName); 

Un rapide coup d’œil avec Reflector confirme que cela vous donnera la logique de la mémoire tampon partielle et le Dispose() les exceptions de votre stream.

Et lorsque les futures versions du Framework permettront de meilleures façons de le faire, votre code en tirera automatiquement profit.