C: la Lecture d'un fichier texte (avec la variable de la longueur des lignes), ligne par ligne, à l'aide de fread()/fgets() au lieu de fgetc() (bloc d'e/S et de caractère I/O)

Est-il un getline fonction qui utilise fread (bloc I/O) au lieu de fgetc (caractère I/O)?

Il y a une perte de performance pour la lecture d'un fichier caractère par caractère par fgetc. Nous pensons que pour améliorer les performances, nous pouvons utiliser le bloc lit via fread dans la boucle intérieure de la getline. Toutefois, cela introduit potentiellement indésirable effet de lire après la fin d'une ligne. Au moins, cela nécessiterait la mise en œuvre de getline de garder une trace de la "non-lu" une partie du fichier, ce qui nécessite une couche d'abstraction au-delà de la norme ANSI C sémantique de FICHIER. Ce n'est pas quelque chose que nous voulons mettre en œuvre nous-mêmes!

Nous avons profilé de notre application, et le ralentissement des performances est isolé sur le fait que nous sommes de consommer de gros fichiers, caractère par caractère par fgetc. Le reste de la surcharge a fait un trivial coût par comparaison. Nous sommes toujours à la séquentiellement la lecture de chaque ligne du fichier, du début à la fin, et on peut verrouiller le dossier complet de la durée de la lecture. C'est probablement ce qui rend une freadà base de getline plus facile à mettre en œuvre.

Oui, une getline fonction qui utilise fread (bloc I/O) au lieu de fgetc (caractère I/O) existent? Nous sommes à peu près sûr qu'il fait, mais si non, comment devrions-nous mettre en œuvre?

Mise à jour Trouvé un article utile, Manipulation de la Saisie de l'Utilisateur en C, par Paul Hsieh. C'est un fgetcapproche, mais il a une discussion intéressante sur les solutions de rechange (à commencer par la mauvaise gets est, puis discuter fgets):

D'autre part, la commune de la cornue de programmeurs C (même ceux qui sont considérés comme de l'expérience) est-à-dire que fgets() devrait être utilisé comme une alternative. Bien sûr, par lui-même, fgets() n'est pas vraiment gérer la saisie de l'utilisateur en soi. En plus d'avoir un drôle de fin de chaîne condition (lors de la rencontre \n ou expressions du FOLKLORE, mais pas \0), le mécanisme choisi pour la résiliation lorsque la mémoire tampon a atteint la capacité maximale est de simplement brusquement stopper la fgets() de fonctionnement et d' \0 y mettre fin. Donc, si la saisie de l'utilisateur dépasse la longueur de la préaffectés tampon, fgets() retourne un résultat partiel. Pour faire face à cette programmeurs ont deux choix; 1), il suffit de traiter avec tronquée de l'utilisateur (il n'y a aucun moyen de feed-back à l'utilisateur que l'entrée a été tronqué, alors qu'ils sont à fournir en entrée) 2) Simuler une cultivables tableau de caractères et de le remplir avec des appels successifs à fgets(). La première solution, est presque toujours une mauvaise solution pour la variable de la longueur de la saisie de l'utilisateur parce que la mémoire tampon sera inévitablement trop grand la plupart du temps parce que sa en essayant de capturer trop nombreux sont les cas ordinaires, et trop petit pour les cas inhabituels. La deuxième solution est bien sauf qu'il peut être compliqué à mettre en œuvre correctement. Ne traite pas fgets' étrange comportement à l'égard de '\0'.

Exercice laissé au lecteur: afin de déterminer le nombre d'octets a été vraiment lu par un appel à fgets(), on pourrait, par la numérisation, tout comme il le fait, pour un '\n' et sauter par-dessus tout '\0' en ne dépassant pas la taille transmis à fgets(). Expliquer pourquoi ce qui est insuffisant pour la dernière ligne d'un cours d'eau. Quelle faiblesse de ftell() l'empêche de s'attaquer à ce problème complètement?

Exercice laissé au lecteur: Résoudre le problème de la détermination de la longueur des données consommées par fgets() en remplacement de la totalité de la mémoire tampon avec une valeur différente de zéro entre chaque appel à fgets().

Donc, avec fgets() qui nous a laissé le choix d'écrire beaucoup de code et de vivre avec une terminaison de ligne condition qui est en contradiction avec le reste de la bibliothèque C, ou avoir une limite arbitraire. Si ce n'est pas assez bon, alors, que nous reste-il? scanf() mélanges de l'analyse à lire d'une manière qui ne peuvent être séparées, et fread() lira au-delà de la fin de la chaîne. En bref, la bibliothèque C, nous laisse avec rien. Nous sommes obligés de rouler nos propres fondées sur le dessus de fgetc() directement. Donc permet de donner un coup de feu.

Oui, une getline fonction qui est basé sur fgets (et de ne pas tronquer l'entrée) existent?

  • Pour votre nouvelle question à la fin, oui, ça existe. Je l'ai décrit dans ma réponse. L'article que vous avez cité mentionne un problème avec un final de non-retour à la ligne à terminaison de ligne; j'ai fait un non-problème en pré-remplissage de la mémoire tampon avec '\n' et de fournir un moyen de détecter l'état.
  • Notez également que Paul Hsieh est la solution à utiliser fgetc est très mauvais. Sur les implémentations modernes, en raison de l'exigence à l'appui de verrouillage dans le cas où plusieurs threads accèdent à la même FILE objet, à l'aide de fgetc sera très lent. Vous pouvez utiliser getc_unlocked (mais c'est une fonction POSIX, pas un standard C de la fonction), mais même avec une optimale macro extension de getc_unlocked, la façon fgets recherches de la mémoire tampon pour '\n' (c'est à dire à l'aide de memchr) sera beaucoup plus rapide que ce que vous pouvez faire sans accès à la mémoire tampon interne. Notez également que si vous avez POSIX (2008), vous avez getline déjà.