web-dev-qa-db-fra.com

Quelle est la raison pour laquelle fread/fwrite prend la taille et compte comme arguments?

Au travail, nous avons discuté de la raison pour laquelle fread et fwrite prennent une taille par membre et comptent et renvoient le nombre de membres lus/écrits plutôt que de simplement prendre un tampon et une taille. La seule utilisation que nous pourrions en tirer est si vous voulez lire/écrire un tableau de structures qui ne sont pas divisibles de manière égale par l'alignement de la plate-forme et qui ont donc été complétées mais qui ne peuvent pas être assez communes pour justifier ce choix. dans la conception.

De FREAD (3) :

La fonction fread () lit les éléments nmemb des données, chaque octet de la longueur, à partir du flux pointé par flux, en les stockant à l'emplacement indiqué par ptr.

La fonction fwrite () écrit des éléments nmemb de données, chaque octet de taille longtemps, au flux pointé par flux, les obtenant de l'emplacement donné par ptr.

fread () et fwrite () renvoient le nombre d'éléments lus ou écrits avec succès (c’est-à-dire pas le nombre de caractères). Si une erreur survient, ou le la fin du fichier est atteinte, la valeur de retour est un nombre d’items court (ou zéro).

81
David Holm

C'est basé sur comment fread est implémenté.

La spécification UNIX unique dit

Pour chaque objet, les appels de taille doivent être fait à la fonction fgetc () et le les résultats stockés, dans l'ordre de lecture, dans un tableau de caractères non signés exactement superposer l'objet.

fgetc a aussi cette note:

Puisque fgetc () opère sur des octets, lire un caractère composé de Plusieurs octets (ou "un caractère multi-octets ") peuvent nécessiter plusieurs appels fgetc ().

Bien entendu, cela est antérieur aux codages de caractères à octets variables sophistiqués tels que UTF-8.

Le SUS note que cela provient en fait des documents ISO C.

18
Powerlord

La différence entre fread (buf, 1000, 1, stream) et fread (buf, 1, 1000, stream) est que, dans le premier cas, vous n’obtenez qu’un bloc de 1000 octets ou nuthin, si le fichier est plus petit et dans le Dans le second cas, le fichier contient moins de 1000 octets.

58
Peter Miehle

C’est une pure spéculation, mais à l’époque (certains sont toujours là), de nombreux systèmes de fichiers ne sont pas de simples flux d’octets sur un disque dur. 

De nombreux systèmes de fichiers étaient basés sur des enregistrements. Ainsi, pour satisfaire ces systèmes de fichiers de manière efficace, vous devez spécifier le nombre d'éléments ("records"), ce qui permet à fwrite/fread de fonctionner sur le stockage en tant qu'enregistrements, et pas uniquement en flux d'octets.

12
nos

Ici, laissez-moi corriger ces fonctions:

size_t fread_buf( void* ptr, size_t size, FILE* stream)
{
    return fread( ptr, 1, size, stream);
}


size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
{
    return fwrite( ptr, 1, size, stream);
}

Pour ce qui est de justifier les paramètres de fread()/fwrite(), j'ai perdu ma copie de K & R il y a longtemps, donc je ne peux que deviner. Je pense que la réponse probable est que Kernighan et Ritchie ont peut-être simplement pensé que l'exécution des E/S binaires se ferait le plus naturellement sur des tableaux d'objets. En outre, ils ont peut-être pensé que les E/S de bloc seraient plus rapides/plus faciles à implémenter ou peu importe sur certaines architectures.

Même si la norme C spécifie que fread() et fwrite() soient implémentés en termes de fgetc() et fputc(), rappelez-vous que la norme est apparue bien après que C & R a défini C que les éléments spécifiés dans la norme peuvent ne pas avoir été dans les idées des concepteurs d'origine. Il est même possible que les choses dites dans "Le langage de programmation C" de K & R ne soient pas les mêmes que lors de la conception du langage.

Enfin, voici ce que P.J. Plauger a à dire à propos de fread() dans "The Standard C Library":

Si l'argument size (deuxième) est supérieur à un, vous ne pouvez pas déterminer si la fonction lit également jusqu'à size - 1 caractères supplémentaires au-delà de ce qu'elle indique. En règle générale, il vaut mieux appeler la fonction fread(buf, 1, size * n, stream); au lieu de fread(buf, size, n, stream);

Fondamentalement, il dit que l'interface de fread() est cassée. Pour fwrite(), il note que "les erreurs d'écriture sont généralement rares, ce n'est donc pas un inconvénient majeur" - une déclaration avec laquelle je ne suis pas d'accord.

9
Michael Burr

Cela revient probablement à la façon dont cette E/S de fichier a été implémentée. (retour dans la journée) Il aurait peut-être été plus rapide d'écrire/lire dans des fichiers en blocs que de tout écrire en une fois.

3
dolch

Je pense que c’est parce que C manque de surcharge de fonctions. S'il y en avait, la taille serait redondante. Mais en C, vous ne pouvez pas déterminer la taille d'un élément de tableau, vous devez en spécifier une.

Considère ceci:

int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);

Si vous écrivez le nombre d'octets accepté, vous pouvez écrire ce qui suit:

int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);

Mais c'est simplement inefficace. Vous aurez sizeof (int) fois plus d'appels système.

Un autre point à prendre en considération est que vous ne voulez généralement pas qu'une partie d'un élément de tableau soit écrite dans un fichier. Vous voulez l'entier entier ou rien. fwrite renvoie un certain nombre d'éléments écrits avec succès. Donc, si vous découvrez que seulement 2 octets bas d'un élément est écrit, que feriez-vous?

Sur certains systèmes (en raison de l'alignement), vous ne pouvez pas accéder à un octet de nombre entier sans créer de copie et de décalage.

1
Vanuan

Disposer d'arguments distincts pour la taille et le nombre pourrait être avantageux pour une implémentation évitant la lecture d'enregistrements partiels. Si vous utilisiez des lectures sur un octet à partir de quelque chose comme un canal, même si vous utilisiez des données à format fixe, il faudrait prévoir la possibilité de séparer un enregistrement en deux lectures. If pourrait au contraire demander par exemple une lecture non bloquante de 40 enregistrements de 10 octets maximum quand il y a 293 octets disponibles et que le système renvoie 290 octets (29 enregistrements entiers) tout en laissant 3 octets prêts pour la lecture suivante, ce serait beaucoup plus pratique.

Je ne sais pas dans quelle mesure les implémentations de fread peuvent gérer une telle sémantique, mais elles pourraient certainement être utiles pour les implémentations qui pourraient promettre de les prendre en charge.

0
supercat