- Apprendre
- Informatique et numérique
- Programmation
- Langage C : pointeurs, mémoire et structures
- Entrées et sorties de fichiers en C
Entrées et sorties de fichiers en C
fgets. Stocke des tableaux et des enregistrements dans des fichiers binaires avec fread et fwrite, conçois des formats de fichiers lisibles correctement sur d’autres machines et accède directement à n’importe quel enregistrement avec fseek. Tout au long de l’unité, vérifie chaque résultat, explique les échecs avec errno et libère les ressources pour que tes programmes échouent sans danger et indiquent fidèlement le résultat de leurs opérations.DébutantUnité 7 sur 8 de la formation Formation : Langage C : pointeurs, mémoire et structures
Ce que tu vas apprendre
- Expliquer comment les programmes C accèdent aux fichiers par des flux mis en tampon, ouvrir et fermer les fichiers dans le mode adapté et utiliser les trois flux standard avec des redirections en ligne de commande.
- Expliquer les flux, la mise en tampon et la différence entre mode texte et mode binaireDécrire ce que sont un flux et un
FILE *, le fonctionnement de la mise en tampon et de la position dans le fichier, ainsi que les différences entre mode texte et mode binaire sous Windows et sur les systèmes de type Unix. - Ouvrir et fermer des fichiers avec fopen et fcloseOuvrir un fichier dans le mode adapté à la tâche, vérifier son ouverture, trouver les fichiers à partir de leur chemin et fermer chaque flux une fois le travail terminé.
- Utiliser stdin, stdout et stderr avec des redirections et des tubesUtiliser les trois flux avec lesquels chaque programme C démarre, envoyer les résultats et les messages d’erreur au bon endroit et permettre aux utilisateurs de les rediriger depuis la ligne de commande.
- Expliquer les flux, la mise en tampon et la différence entre mode texte et mode binaire
- Traiter les fichiers texte caractère par caractère, par lectures et écritures formatées et ligne par ligne, en choisissant une méthode sûre pour chaque cas et en testant chaque résultat.
- Lire et écrire caractère par caractèreUtiliser fgetc et fputc avec une variable int, s’arrêter correctement en fin de fichier, puis compter, copier et transformer du texte caractère par caractère.
- Écrire et lire du texte formaté avec fprintf et fscanfÉcrire des nombres et des chaînes dans des fichiers selon une présentation choisie, construire des noms de fichiers avec sprintf et lire des données formatées avec fscanf en vérifiant combien d’éléments ont été convertis.
- Lire des lignes en toute sécurité avec fgetsLire du texte ligne par ligne avec fgets, gérer les caractères de fin de ligne, les lignes longues et les fins de ligne Windows, puis analyser chaque ligne après sa lecture.
- Lire et écrire caractère par caractère
- Écrire et lire des octets bruts, des tableaux et des structures avec fwrite et fread, puis concevoir des formats de fichiers binaires lisibles correctement sur d’autres machines.
- Lire et écrire des données binaires avec fread et fwriteUtiliser fread et fwrite avec la taille et le nombre d’éléments adaptés, copier des fichiers par blocs, reconnaître les types de fichiers à leurs premiers octets et stocker des tableaux et des structures.
- Concevoir des formats binaires utilisables sur différentes machinesExpliquer comment la taille des types, le boutisme et le bourrage des structures rendent les fichiers binaires bruts dépendants de la machine, puis lire et écrire des champs de plusieurs octets selon un format défini.
- Lire et écrire des données binaires avec fread et fwrite
- Obtenir et modifier la position dans le fichier pour accéder directement aux données nécessaires, puis mettre à jour en place des enregistrements de taille fixe sans réécrire tout le fichier.
- Obtenir et modifier la position dans le fichier avec ftell, fseek et rewindIndiquer la position courante, se déplacer par rapport au début, à la position courante ou à la fin, calculer les décalages des enregistrements et les tailles de fichiers, et connaître les restrictions applicables aux flux texte.
- Mettre à jour en place des enregistrements de taille fixeOuvrir un fichier en lecture et en écriture, respecter la règle de passage de l’une à l’autre et modifier, ajouter ou supprimer des enregistrements sans corrompre le fichier.
- Obtenir et modifier la position dans le fichier avec ftell, fseek et rewind
- Vérifier le résultat de chaque opération sur un fichier, expliquer les échecs à l’utilisateur avec errno et libérer chaque ressource pour que les programmes échouent sans danger et indiquent fidèlement leur réussite.
- Vérifier chaque résultat et distinguer la fin de fichier des erreursSavoir comment chaque fonction de stdio signale un échec, utiliser feof et ferror après la fin d’une boucle de lecture et détecter les erreurs d’écriture qui n’apparaissent que lorsque le tampon est écrit.
- Expliquer les échecs avec errno, perror et strerrorUtiliser errno pour comprendre pourquoi un appel à la bibliothèque a échoué et afficher des messages d’erreur clairs qui indiquent le programme, le fichier et la raison.
- Libérer les ressources et indiquer le résultat de l’opérationFermer chaque flux sur tous les chemins, ne laisser aucun fichier de sortie partiellement écrit et renvoyer un code de retour qui reflète fidèlement le résultat.
- Vérifier chaque résultat et distinguer la fin de fichier des erreurs
Entrées et sorties de fichiers en C : cours
1Ouvrir des fichiers sous forme de flux et relier les programmes à leurs entrées et sorties
Les fichiers sont accessibles à un programme par des flux, qui contrôlent l’accès, la mise en tampon et la position. Le choix d’un mode peut préserver les anciennes données, les effacer ou imposer chaque écriture à la fin : l’ouverture fait donc partie de la conception du programme. Les trois flux standard étendent la même interface aux terminaux, aux fichiers redirigés et aux tubes. Comprendre leurs connexions permet d’écrire une même fonction de traitement utilisable dans plusieurs situations et de séparer les diagnostics des résultats utiles.
1.1 Expliquer les flux, la mise en tampon et la différence entre mode texte et mode binaire
Un fichier contient des données stockées ; un flux est le canal qu’un programme en cours d’exécution utilise pour y accéder. Les mêmes fonctions opérant sur des flux peuvent aussi fonctionner avec un terminal ou un tube. Inclus <stdio.h> et conserve le pointeur du flux dans une variable de type FILE *.
Ce que le flux mémorise
L’objet FILE de la bibliothèque suit l’état d’un tampon, la position courante dans le fichier ainsi que les indicateurs de fin de fichier et d’erreur. Passe son pointeur à des fonctions comme fgetc et fprintf ; n’examine ni ne modifie ses champs. Une lecture ou une écriture fait avancer la position au-delà des données traitées. Dans un fichier binaire commençant par "hello\nworld\n", la lecture des six premiers octets place la lecture suivante au w.
La mise en tampon regroupe les petites opérations en transferts plus importants. Une écriture réussie peut signifier que les données ont atteint un tampon en mémoire, tandis que leur transfert au système d’exploitation reste en attente. fflush(fp) envoie au système d’exploitation les sorties en attente. fclose(fp) fait de même avant de libérer le flux. Aucun des deux ne garantit que les données résisteront à une coupure soudaine de courant.
| Mode de mise en tampon | Moment du transfert des sorties |
|---|---|
| Entièrement mis en tampon | Lorsque le tampon est plein, vidé explicitement ou fermé |
| Mis en tampon par ligne | Aussi lorsqu’un caractère de fin de ligne est écrit |
| Non mis en tampon | Dès que possible |
Les fichiers ordinaires ouverts avec fopen sont entièrement mis en tampon. Les périphériques interactifs peuvent utiliser une autre mise en tampon. Un terminal ou un tube ne fournit pas de positions ordinaires permettant de se déplacer en avant et en arrière dans un fichier.
Choisir le mode texte ou binaire
Le mode texte traite des lignes lisibles par une personne. Le mode binaire préserve les valeurs des octets sans traduction de texte. Ajoute b au mode d’ouverture pour les données binaires : "rb" les lit et "wb" les écrit. Les images, les données compressées et les enregistrements bruts exigent le mode binaire, même si une version en mode texte semble fonctionner sur ton ordinateur.
Sous Linux et macOS, une fin de ligne est représentée par un octet LF, 0x0A, et les deux modes se comportent normalement de la même façon. Sous Windows, la sortie en mode texte traduit '\n' en deux octets CR LF, 0x0D 0x0A. L’entrée en mode texte traduit CR LF en un seul '\n'. L’entrée en mode texte de Microsoft reconnaît aussi 0x1A, Ctrl+Z, comme une fin de fichier.
Par exemple, écrire "a\nb\nc\n" en mode texte produit six octets sous Linux ou macOS et neuf sous Windows. Les trois lettres occupent trois octets ; les trois fins de ligne Windows en occupent six. La lecture du fichier Windows en mode texte sous Windows donne six caractères, tandis que le mode binaire donne accès aux neuf octets.
Distinguer les octets du fichier de son texte
Une ligne créée sous Windows et lue sous Linux peut conserver "\r\n". Supprimer seulement '\n' laisse '\r', ce qui peut faire échouer une comparaison avec "yes". Une position dans un flux texte peut aussi refléter l’état de la traduction ; enregistre et restaure donc les positions dans un flux texte au lieu de calculer des décalages en octets.
La garantie du C selon laquelle le texte est restitué exactement s’applique aux caractères imprimables, aux tabulations et aux caractères de fin de ligne, sans espace immédiatement avant une fin de ligne et avec un caractère de fin de ligne à la fin de la dernière ligne. Les autres suites d’octets doivent être placées dans des flux binaires. Les octets en C comptent au moins huit bits ; les exemples portant sur des valeurs d’octets de 0 à 255 et sur les formats de fichiers courants utilisent des octets de huit bits.
Points clés
- Un
FILE *donne aux fonctions de bibliothèque accès à un flux et à son état. - Les sorties mises en tampon peuvent échouer lors du vidage du tampon ou de la fermeture ; vérifie ces résultats.
- Sous Windows, le mode texte traduit les fins de ligne ; le mode binaire préserve les octets.
- Enregistre les positions dans les flux texte ; calcule les décalages dans les fichiers binaires.
- Précise que tu supposes les octets sur huit bits lorsque tu interprètes des formats binaires courants.
1.2 Ouvrir et fermer des fichiers avec fopen et fclose
Choisis un mode d’ouverture avant d’écrire le code de traitement. Le mode détermine si le fichier doit exister, si son contenu est conservé et où les écritures ont lieu. fopen agit immédiatement sur le fichier : une ouverture réussie avec "w" efface un fichier existant, même si aucune écriture n’a lieu ensuite.
Adapter le mode à la tâche
| Mode | Fichier existant | Fichier absent | Accès |
|---|---|---|---|
"r" | Conserve le contenu | Échoue | Lecture depuis le début |
"w" | Efface le contenu | Crée le fichier | Écriture depuis le début |
"a" | Conserve le contenu | Crée le fichier | Écriture à la fin |
"r+" | Conserve le contenu | Échoue | Lecture et écriture |
"w+" | Efface le contenu | Crée le fichier | Lecture et écriture |
"a+" | Conserve le contenu | Crée le fichier | Lecture partout ; écriture à la fin |
Ajoute b pour le mode binaire ; "r+b" et "rb+" ont le même sens. C11 ajoute la création exclusive avec x dans les modes d’écriture, comme "wx" et "wbx" : l’ouverture échoue si le fichier existe. Utilise une chaîne de mode documentée ; les lettres de mode supplémentaires ne sont pas portables.
Vérifier avant d’utiliser le pointeur
fopen renvoie un pointeur vers un nouveau flux si l’ouverture réussit et NULL en cas d’échec. Un fichier absent, un chemin inaccessible ou un répertoire manquant peuvent tous provoquer un échec.
FILE *fp = fopen("scores.txt", "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open scores.txt\n");
return EXIT_FAILURE;
}
/* Read through fp here. */
if (fclose(fp) == EOF) {
fprintf(stderr, "Cannot close scores.txt\n");
return EXIT_FAILURE;
}
Cet extrait utilise <stdio.h> et <stdlib.h>. Des fonctions comme fgetc, fprintf et fclose ont besoin d’un flux valide ; leur passer NULL est un comportement indéfini. fflush(NULL) est une exception volontaire qui vide les tampons de tous les flux de sortie.
fclose renvoie 0 si la fonction réussit et EOF en cas d’échec. Une fois que la fonction a été appelée, le flux est fermé, y compris lorsque la fermeture signale une erreur. Ne rappelle pas fclose sur le même pointeur et ne l’utilise plus pour des entrées-sorties. Ferme rapidement les fichiers : les flux disponibles sont limités et le C garantit la prise en charge d’au moins huit flux ouverts, dont les trois flux standard.
Résoudre les chemins à partir du programme en cours d’exécution
Un chemin relatif comme "data/input.txt" part du répertoire de travail courant, et non du dossier du fichier source. Lancer le programme ailleurs change ce que désigne ce chemin. Les barres obliques fonctionnent aussi avec la bibliothèque C de Microsoft. Une barre oblique inverse dans une chaîne C doit être doublée, comme dans "C:\\data\\in.txt" ; sinon, une séquence d’échappement comme \n peut modifier la chaîne.
Pour les noms fournis en ligne de commande, utilise int main(int argc, char *argv[]). Dans une commande de copie avec deux noms, argc doit valoir 3, argv[1] est le nom de l’entrée et argv[2] celui de la sortie. Ouvre d’abord l’entrée pour qu’un nom d’entrée mal saisi ne crée ni n’efface la sortie. Si l’ouverture de la sortie échoue, ferme l’entrée déjà ouverte. Utilise des fichiers d’entrée et de sortie distincts : ouvrir d’abord l’entrée ne la protège pas si le nom de sortie désigne le même fichier.
Un retour normal de main ou un appel à exit ferme les flux, mais les fermetures explicites permettent au programme de détecter les erreurs de sortie tardives. Un plantage peut faire perdre les données mises en tampon ; abort ne garantit pas la libération des ressources associée à une sortie normale.
Points clés
- Une ouverture avec
"w"efface immédiatement un fichier existant. - Vérifie que
fopenn’a pas renvoyéNULLavant d’utiliser le flux. - Les chemins relatifs partent du répertoire de travail courant.
- Ferme chaque flux ouvert une seule fois et ne le réutilise jamais après
fclose. - Ouvre l’entrée de la copie avant la sortie et utilise des fichiers distincts.
- Les modes d’écriture exclusifs de C11 échouent lorsque la destination existe.
1.3 Utiliser stdin, stdout et stderr avec des redirections et des tubes
Un programme C démarre avec trois flux ouverts : l’entrée standard stdin, la sortie standard stdout et la sortie d’erreur standard stderr. Ils sont généralement reliés au terminal, mais l’interpréteur de commandes peut les relier à des fichiers ou à d’autres programmes. Tu peux les passer directement aux fonctions opérant sur des flux.
Séparer les résultats des diagnostics
printf écrit dans stdout ; scanf lit dans stdin. getchar() lit un caractère dans stdin, et putchar(c) en écrit un dans stdout. puts(s) écrit une chaîne dans stdout et ajoute un caractère de fin de ligne. Leurs formes opérant sur des flux permettent au même code de fonctionner avec un fichier :
void print_total(FILE *out, int total)
{
fprintf(out, "Total: %d\n", total);
}
L’appel print_total(stdout, 12) affiche un résultat ; passer un pointeur vers un fichier ouvert envoie la même présentation dans ce fichier. Dans du code de production, fais en sorte que la fonction auxiliaire signale un échec d’écriture à sa fonction appelante.
Écris les diagnostics avec fprintf(stderr, ...). Un programme de traitement de données peut alors produire un fichier de résultats propre tout en expliquant les échecs séparément. Une erreur affichée dans stdout peut corrompre les données qu’un autre programme s’attend à lire.
Laisser l’interpréteur de commandes choisir les connexions
Dans un interpréteur de commandes de type Unix, cette commande sépare les trois flux :
./sortnums < numbers.txt > sorted.txt 2> errors.txt
< fournit l’entrée, > crée ou remplace la sortie, >> ajoute à la sortie et 2> redirige les erreurs. Les opérateurs de redirection fonctionnent aussi dans l’invite de commandes Windows, où le nom du programme s’écrit généralement sortnums.exe. Un tube, comme dans generate | sortnums, envoie la sortie standard du premier programme vers l’entrée standard du second. Il ne transporte pas stderr par défaut.
Un filtre peut accepter un nom d’entrée facultatif et, à défaut, lire stdin. Suis la propriété des ressources : ferme un flux que ta fonction a ouvert, mais laisse un flux emprunté à son propriétaire. Pour un filtre simple en ligne de commande, if (in != stdin) permet de reconnaître le fichier qu’il a lui-même ouvert.
Vider les tampons des invites avant d’attendre une entrée
Un terminal entraîne généralement une mise en tampon de stdout par ligne. Un fichier redirigé ou un tube entraîne généralement sa mise en tampon complète. stderr n’est pas entièrement mis en tampon. Cela explique pourquoi l’ordre des sorties peut changer lorsque les deux flux sont envoyés vers une même destination.
Après printf("Saving..."), le texte peut rester dans le tampon en l’absence de caractère de fin de ligne. Utilise fflush(stdout) et vérifie si la fonction renvoie EOF lorsque le texte doit apparaître avant l’opération suivante. Vider le tampon transmet les sorties en attente ; cela ne lit ni n’élimine les entrées. Le C standard ne définit pas fflush(stdin) comme une opération permettant de vider l’entrée. Pour ignorer une ligne, lis les caractères jusqu’à '\n' ou EOF.
Si un programme affiche deux lignes dans stdout et un avertissement dans stderr entre les deux, un terminal les affichera généralement dans l’ordre du programme. Avec > out.txt 2>&1, l’avertissement peut atteindre le fichier avant la sortie standard mise en tampon. N’utilise pas l’ordre d’affichage des flux mélangés comme trace de l’ordre d’exécution.
Renvoyer un résultat exploitable par les scripts
Renvoie EXIT_SUCCESS ou 0 lorsque toute la tâche réussit et EXIT_FAILURE lorsqu’elle échoue. Les deux macros sont déclarées dans <stdlib.h>. Une commande comme convert in.csv out.txt && echo done n’exécute la seconde commande qu’après une réussite. Un code de retour fidèle au résultat compte autant qu’un diagnostic utile.
Points clés
- Utilise
stdin,stdoutetstderrsans les ouvrir. - Envoie les résultats du programme vers
stdoutet les diagnostics versstderr. - La redirection modifie les connexions ; un tube transmet la sortie standard à l’entrée standard.
- Vide le tampon de sortie lorsqu’une invite doit être visible immédiatement.
- Renvoie un code de retour indiquant l’échec lorsque la tâche demandée échoue.
2Lire et écrire des fichiers texte
Le traitement du texte peut se faire à trois niveaux utiles : les caractères individuels, les valeurs formatées et les lignes entières. Ce choix modifie ce que le programme peut valider et la façon dont il se remet d’une entrée incorrecte. Une boucle de lecture des caractères doit distinguer les octets de la fin de fichier ; une lecture formatée doit vérifier son nombre d’affectations réussies ; une lecture de ligne doit gérer la capacité et les enregistrements incomplets. Des exemples détaillés montrent comment préserver les données effectivement lues tout en maîtrisant leur analyse et le signalement des problèmes.
2.1 Lire et écrire caractère par caractère
Les entrées-sorties caractère par caractère sont utiles lorsque chaque caractère détermine la suite du traitement : compter des séparateurs, changer la casse ou reconnaître un petit format texte. fgetc lit un caractère et fputc en écrit un. Les deux fonctions sont déclarées dans <stdio.h>.
Conserver la valeur de retour dans un int
fgetc(fp) renvoie le caractère sous forme d’un unsigned char converti en int, ou la constante négative EOF lorsqu’aucun caractère n’est disponible parce que l’entrée est terminée ou qu’une lecture a échoué. Sur les systèmes courants dont les octets comptent huit bits, les valeurs valides des octets vont de 0 à 255. Un int permet de distinguer ces valeurs de EOF.
int c;
while ((c = fgetc(in)) != EOF) {
if (fputc(c, out) == EOF) {
/* Report a write failure and clean up. */
break;
}
}
/* Check ferror(in) before declaring the input complete. */
Un simple char peut perdre cette distinction. Avec un char signé, l’octet 0xFF peut devenir -1 et ressembler à une fin de fichier. Avec un char non signé, la valeur négative EOF est convertie en octet et ne peut jamais être égale à EOF lors d’une comparaison.
Conserve les deux parenthèses autour de l’affectation. Dans c = fgetc(in) != EOF, la comparaison a lieu en premier : c reçoit donc 1 ou 0 au lieu du caractère. getc effectue la même lecture et peut être une macro ; fputc renvoie le caractère écrit ou EOF.
Compter les lectures réussies, pas les tentatives
La condition de la boucle doit effectuer la lecture. feof décrit une tentative précédente qui a atteint la fin ; il ne peut pas prédire la tentative suivante. Une boucle qui vérifie !feof(in) puis compte sans condition ajoute un passage supplémentaire à la fin.
Pour le texte "hi\nyo\n", six lectures réussies donnent six caractères et deux caractères de fin de ligne. Compter uniquement les caractères de fin de ligne fonctionne pour les lignes qui se terminent par un tel caractère. Le texte "red\ngreen\nblue" contient deux caractères de fin de ligne mais trois lignes, car le dernier "blue" est une ligne à part entière.
Pour inclure une dernière ligne sans caractère de fin de ligne, suis aussi le dernier caractère :
size_t lines = 0;
int c, last = '\n';
while ((c = fgetc(in)) != EOF) {
if (c == '\n') ++lines;
last = c;
}
if (last != '\n') ++lines;
Initialiser last à '\n' permet de compter zéro ligne pour un fichier vide. Une erreur de lecture exige toujours un chemin de traitement distinct ; un comptage partiel n’est pas un résultat complet.
Transformer ou examiner le caractère suivant
toupper de <ctype.h> peut modifier les lettres avant leur écriture. Le résultat d’un fgetc réussi se trouve déjà dans la plage des valeurs d’entrée valides pour toupper ; fputc(toupper(c), out) est donc sûr dans la boucle. Les valeurs char signées quelconques doivent être converties en unsigned char avant d’être passées aux fonctions de classification des caractères.
ungetc(c, in) remet un caractère dans le flux pour que la lecture suivante le renvoie à nouveau. La remise d’un caractère est garantie ; vérifie si la fonction renvoie EOF en cas d’échec. Cela permet à un analyseur d’examiner le caractère suivant sans le perdre. Une opération de positionnement annule la remise du caractère.
Le comptage décrit ce que fournit le mode de flux choisi. Sous Windows, le mode texte compte une paire CR LF comme un seul '\n' ; le mode binaire donne accès aux deux octets. Un nombre de caractères obtenu par un flux texte n’est donc pas nécessairement égal au nombre d’octets stockés.
Points clés
- Conserve les résultats de
fgetcdans unintpour distinguer les valeurs des octets deEOF. - Teste chaque résultat de lecture avant de le traiter ou de le compter.
- Compte comme une ligne un dernier morceau non vide sans caractère de fin de ligne.
- La remise d’un caractère avec
ungetcest garantie ; un positionnement l’annule.
2.2 Écrire et lire du texte formaté avec fprintf et fscanf
Les entrées-sorties formatées convertissent les valeurs C en texte lisible et inversement. fprintf écrit selon une présentation que tu choisis ; fscanf lit des valeurs qui correspondent à un format. Leurs spécifications de conversion se ressemblent, mais l’entrée exige des pointeurs vers des destinations de types adaptés.
Écrire des valeurs lisibles
Utilise %d pour un int, %ld pour un long, %zu pour un size_t, %s pour une chaîne et %c pour un caractère. En sortie, %f affiche un double ; un argument float est promu en double. %% affiche un signe pourcentage.
int result = fprintf(fp, "%-8s%6.2f\n", "Oslo", 3.14159);
if (result < 0) {
/* Handle a write failure. */
}
%-8s aligne "Oslo" à gauche sur huit colonnes ; %6.2f aligne "3.14" à droite sur six colonnes. La ligne obtenue est "Oslo 3.14\n" et la valeur renvoyée est de 15 caractères. La largeur de champ est un minimum, et non une limite de longueur de sortie. La précision modifie aussi l’information stockée : %.2f écrit 3.14159 sous la forme "3.14" ; les chiffres supplémentaires ne peuvent donc pas être récupérés depuis le fichier.
Une fonction simple d’écriture CSV peut produire "Lima,2024,19.5" avec un ordre fixe et des virgules entre les champs. Le texte qui contient des virgules, des guillemets ou des caractères de fin de ligne doit être mis entre guillemets selon les règles CSV. Place un tel champ entre guillemets doubles et double tout guillemet à l’intérieur. Une fonction qui écrit avec un simple %s ne convient que si les champs texte ne contiennent aucun de ces caractères.
Formater dans un tableau de capacité limitée
sprintf n’a pas d’argument indiquant la taille de la destination. Formater "007.jpg" exige huit octets, caractère nul de fin de chaîne compris. Préfère snprintf :
char name[32];
int n = snprintf(name, sizeof name, "%03d.jpg", 7);
if (n < 0 || (size_t)n >= sizeof name) {
/* Formatting failed or the full result did not fit. */
}
La valeur non négative renvoyée est la longueur nécessaire au texte complet, sans compter le caractère nul de fin de chaîne. Une valeur égale à la taille du tampon indique déjà une troncature. Vérifie que le résultat n’est pas négatif avant de le convertir en size_t.
Lire le nombre de valeurs attendu
char name[20];
int age;
int matched = fscanf(fp, "%19s %d", name, &age);
Cet appel ne réussit complètement que s’il renvoie 2. La largeur 19 laisse un octet pour le caractère nul de fin de chaîne. Le nom du tableau fournit son adresse ; l’entier exige &age. En entrée, %f exige un float *, tandis que %lf exige un double *. Une incompatibilité constitue un comportement indéfini et non une conversion sans conséquence.
La plupart des conversions ignorent les caractères blancs qui précèdent les données, y compris les fins de ligne. fscanf n’impose donc pas un enregistrement par ligne, et %s ne peut pas lire "New York" comme une seule valeur. Un ensemble de caractères à lire comme %19[^,] lit jusqu’à une virgule ; lire une ligne entière est souvent plus clair pour les enregistrements.
Avec "10 abc 20", %d stocke d’abord 10 et renvoie 1. L’appel suivant renvoie 0, car "abc" ne correspond pas ; ce texte reste non lu. Tester != EOF répète l’échec indéfiniment. Teste == 1, puis traite les données invalides séparément d’une fin de l’entrée ou d’une erreur de flux. Un résultat de conversion est un nombre de valeurs affectées, pas une valeur de vérité pour tout le fichier.
Points clés
- Fais correspondre chaque spécification de conversion au type de l’argument.
- Limite la largeur de
%sen entrée à la taille du tableau moins un. - Compare le résultat de
fscanfau nombre exact d’affectations attendues. snprintfrenvoie la longueur complète nécessaire ; une valeur au moins égale à la capacité indique une troncature.- Les champs texte CSV doivent être mis entre guillemets lorsqu’ils contiennent des virgules, des guillemets ou des caractères de fin de ligne.
- Une sortie formatée de nombres à virgule flottante peut perdre en précision.
2.3 Lire des lignes en toute sécurité avec fgets
Lire une ligne complète avant de l’analyser permet de garder les enregistrements texte séparés. Si un enregistrement est invalide, tu peux signaler son numéro de ligne et passer au suivant. fgets limite la quantité de données écrites, mais tu dois quand même gérer les caractères de fin de ligne conservés et les lignes plus longues que le tableau.
Lire dans un tableau de capacité connue
char line[256];
while (fgets(line, sizeof line, fp) != NULL) {
/* Process this successful read. */
}
if (ferror(fp)) {
/* Report an interrupted read. */
}
fgets lit au plus un caractère de moins que la capacité, s’arrête après un caractère de fin de ligne s’il en rencontre un et ajoute un caractère nul de fin de chaîne. Il renvoie le tampon si la lecture réussit. Un résultat NULL signifie soit qu’aucun caractère n’était disponible en fin de fichier, soit qu’une erreur s’est produite ; ne traite pas le tampon après une erreur de lecture.
sizeof line fournit la capacité du tableau dans cette portée. Dans une fonction auxiliaire dont le paramètre est char *line, il donne la taille du pointeur. Passe séparément la capacité réelle. L’ancienne fonction gets ne peut pas limiter l’entrée et a été retirée en C11.
Reconnaître les morceaux de lignes longues
Avec char buf[8], "temperature\n" arrive sous la forme "tempera", puis "ture\n". Le premier appel utilise sept octets pour les caractères et un pour le caractère nul de fin de chaîne. Une lecture réussie sans caractère de fin de ligne peut correspondre à un morceau de ligne longue ou au dernier morceau non terminé en fin de fichier.
Choisis une méthode : réunir les morceaux dans un enregistrement plus grand, les traiter comme une suite continue, ou rejeter l’enregistrement et ignorer tous les morceaux restants. Si une limite de taille est fixée, examine le caractère suivant avant de rejeter un tampon exactement rempli. Un caractère de fin de ligne suivant complète l’enregistrement ; EOF sans erreur de flux complète une dernière ligne non terminée ; un autre caractère indique que le contenu se poursuit. Ne remets un caractère dans le flux que si le code qui suit doit le relire.
Ne supprimer qu’une fin de ligne effectivement trouvée
Après avoir déterminé si l’enregistrement est complet, supprime les caractères de fin de ligne :
line[strcspn(line, "\r\n")] = '\0';
strcspn de <string.h> trouve le premier caractère indiqué, ou le caractère nul de fin de chaîne existant si aucun des deux n’est présent. Cela traite aussi bien CR LF conservé que LF. Supprimer systématiquement line[strlen(line) - 1] peut retirer une donnée utile d’une dernière ligne sans caractère de fin de ligne ; cette opération est aussi invalide pour une chaîne vide.
fputs(line, out) écrit la chaîne sans ajouter de caractère de fin de ligne ; puts(line) écrit dans stdout et en ajoute un. Une copie en mode texte peut passer chaque morceau lu avec succès par fgets à fputs, en vérifiant l’absence d’échec, même lorsqu’une ligne longue s’étend sur plusieurs morceaux. Pour obtenir exactement les octets d’origine, utilise plutôt des entrées-sorties binaires par blocs.
Analyser et valider séparément
sscanf(line, "%d %9s", &qty, item) renvoie 2 pour "7 apples" et 0 pour "seven apples". Une analyse échouée ne laisse aucun jeton incorrect bloqué dans le flux d’entrée, car la ligne a déjà été lue. Les conversions numériques avec sscanf exigent toutefois une entrée représentable ; utilise strtol pour vérifier strictement la plage de valeurs.
Pour strtol, remets errno à zéro, passe un pointeur de fin de conversion et vérifie l’absence de chiffres, ERANGE et tout texte inattendu à la fin. Avec "42abc", le résultat 42 n’est qu’un préfixe numérique. Pour un champ entier, autorise les caractères blancs de fin choisis, puis exige la fin de la chaîne. Vérifie la plage du type de destination avant de convertir un long valide en int.
Points clés
fgetsconserve un caractère de fin de ligne s’il tient dans le tampon et réserve toujours de la place pour un caractère nul de fin de chaîne en cas de réussite.- Un tampon plein sans caractère de fin de ligne exige une vérification pour savoir si la ligne est complète.
- Passe explicitement les capacités aux fonctions auxiliaires qui utilisent des pointeurs.
- Utilise
strcspnpour ne supprimer qu’une fin de ligne présente. - Lis d’abord chaque enregistrement, puis analyse-le et valide-le.
- Avec
strtol, vérifie la présence de chiffres, les erreurs de dépassement de plage et les données restantes.
3Stocker et charger des données dans des fichiers binaires
Les fichiers binaires transfèrent les octets des objets sans les convertir en texte lisible. La taille et le nombre d’éléments déterminent comment sont traités les tableaux complets, les enregistrements et les derniers blocs incomplets. Un fichier partagé entre plusieurs machines exige aussi une représentation explicite : largeur des champs, ordre des octets et disposition. La lecture d’une signature n’est que le début de la vérification de cette représentation ; les longueurs et les nombres doivent être validés avant que le programme ne se fie aux données restantes ou n’alloue de l’espace pour elles.
3.1 Lire et écrire des données binaires avec fread et fwrite
Les entrées-sorties binaires transfèrent les octets des objets sans les convertir en nombres ou en mots lisibles. fread et fwrite reçoivent une adresse, une taille d’élément, un nombre d’éléments et un flux. Leurs valeurs de retour comptent les éléments complets : le choix de la taille d’un élément détermine donc ce que le résultat permet de savoir.
Écrire et lire des tableaux
int a[5] = {1, 2, 3, 4, 5};
if (fwrite(a, sizeof a[0], 5, out) != 5) {
/* Handle a write failure. */
}
Sur un système où int occupe quatre octets, cette opération écrit 20 octets et renvoie 5. Une lecture dans un autre tableau de cinq éléments ayant la même représentation peut restituer les valeurs. Utilise "wb" et "rb" pour qu’aucune traduction de texte ne puisse modifier les octets.
Pour un seul objet, passe son adresse : fwrite(&rec, sizeof rec, 1, out). Pour des objets accessibles par un pointeur p, utilise fwrite(p, sizeof *p, count, out). sizeof p mesure le pointeur et &p pointe vers la variable pointeur elle-même. Aucun des deux ne désigne le transfert de données voulu. Lorsque la taille ou le nombre d’éléments vaut zéro, les deux fonctions renvoient zéro sans transférer de données.
Copier exactement les octets lus
unsigned char buf[512];
size_t n;
while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
if (fwrite(buf, 1, n, out) != n) {
/* Handle failure and stop copying. */
break;
}
}
Une taille d’élément de 1 fait de n un nombre d’octets. Une entrée de 1 300 octets fournit 512, 512 et 276 octets, puis zéro. La dernière écriture doit utiliser 276, et non la capacité de 512. Écrire tout le tampon ajoute 236 octets restants des lectures précédentes.
Avec fread(buf, 512, 1, in), la même entrée renvoie 1, 1, puis 0. Les 276 derniers octets ne forment qu’un élément incomplet ; ils ne sont pas comptés et la valeur de cet élément incomplet est indéterminée. Choisis des éléments d’un octet lorsque le dernier bloc incomplet est utile. Choisis des éléments de la taille d’un enregistrement lorsque les enregistrements incomplets doivent être rejetés.
Un résultat de fread inférieur au nombre demandé peut indiquer une fin de fichier ou une erreur. Vérifie ferror après la copie et vérifie fclose sur la sortie : une écriture acceptée dans un tampon peut échouer plus tard. Un en-tête ou un enregistrement incomplet ne doit jamais être traité comme un objet complet.
Examiner les signatures et les objets stockés
Utilise unsigned char pour les octets bruts ; sur les systèmes dont les octets comptent huit bits, ce type contient les valeurs de 0 à 255 sans valeurs négatives. Les données JPEG commencent par 0xFF 0xD8. Les photos d’appareils photo et de téléphones se poursuivent souvent par un marqueur APPn, ce qui produit un motif de récupération allant de FF D8 FF E0 à FF D8 FF EF. Ce motif permet de repérer des fichiers candidats ; valide le format avant de t’y fier. Certains fichiers JPEG utilisent un autre segment ensuite.
Une structure contenant char name[20] et un int score occupe généralement 24 octets. Une écriture brute comprend tous ses octets stockés, y compris le bourrage. Un membre pointeur enregistre une adresse, et non la chaîne pointée. Utilise un tableau intégré ou écris séparément la longueur et les caractères de la chaîne.
Le texte lisible peut occuper plus d’espace : "1000000\n" utilise huit octets sous Linux et neuf en mode texte sous Windows. Un entier de 32 bits encodé explicitement utilise quatre octets de huit bits. Le stockage brut d’objets est compact, mais lie le fichier à la représentation utilisée par le programme qui l’a produit.
Points clés
freadetfwriterenvoient un nombre d’éléments complets, qui n’est pas toujours un nombre d’octets.- Utilise une taille d’élément de 1 lorsque le dernier bloc incomplet est utile.
- Écris le nombre d’octets lus, pas toute la capacité du tampon.
- Un membre pointeur stocké à l’état brut contient une adresse, pas les données pointées.
- Vérifie les transferts incomplets et la fermeture de la sortie.
- Utilise les signatures pour repérer des fichiers candidats, puis valide le fichier.
3.2 Concevoir des formats binaires utilisables sur différentes machines
Un flux binaire préserve les octets, mais deux machines peuvent interpréter les mêmes octets différemment. Un format portable définit le sens de chaque octet au lieu d’adopter la disposition que le compilateur donne à un objet.
Préciser les tailles, l’ordre et la disposition
Trois éléments rendent une copie brute d’objet dépendante de la machine :
| Élément | Ce qui peut différer |
|---|---|
| Taille des types | int peut occuper deux ou quatre octets ; long diffère généralement entre Windows et Linux 64 bits |
| Ordre des octets | L’octet de poids faible ou celui de poids fort peut venir en premier |
| Disposition des structures | Le bourrage et les décalages des membres peuvent changer |
L’ordre petit-boutiste place l’octet de poids faible en premier. L’ordre gros-boutiste place l’octet de poids fort en premier. La valeur 258, soit 0x00000102 en hexadécimal, est représentée par 02 01 00 00 en ordre petit-boutiste et par 00 00 01 02 en ordre gros-boutiste.
Une disposition courante pour une structure contenant un char suivi d’un int occupe huit octets : un octet pour le caractère, trois octets de bourrage et quatre pour l’entier. Les valeurs des octets de bourrage ne sont pas spécifiées. Les types entiers de largeur fixe de <stdint.h>, comme uint32_t, fixent le nombre de bits lorsqu’ils sont disponibles ; ils ne fixent pas l’ordre des octets et ne suppriment pas le bourrage. Les exemples de formats de fichiers courants supposent des octets de huit bits et la disponibilité de ces types.
Décoder explicitement les champs
Lis entièrement quatre octets avant de les interpréter. Pour un champ petit-boutiste :
uint32_t v = (uint32_t)b[0]
| (uint32_t)b[1] << 8
| (uint32_t)b[2] << 16
| (uint32_t)b[3] << 24;
Ici, b est un tableau d’octets non signés. Chaque conversion explicite a lieu avant le décalage, de sorte que le calcul utilise la largeur non signée nécessaire. Pour encoder la valeur, extrais les huit bits de poids faible, puis les huit suivants, et ainsi de suite. Vérifie chaque opération de sortie. Écrire directement v avec fwrite réintroduirait l’ordre des octets de la machine dans le format.
Définir un petit format complet
Un format de scores peut utiliser "SCR1" comme signature de quatre octets, un nombre d’enregistrements petit-boutiste de quatre octets, puis des enregistrements composés de 20 octets pour le nom et de quatre octets petit-boutistes pour le score. La signature indique aussi la version. L’en-tête mesure huit octets ; chaque enregistrement mesure exactement 24 octets.
Cinq enregistrements occupent 128 octets. L’enregistrement d’indice 3 commence à l’octet 80 : il faut sauter les huit octets de l’en-tête et trois enregistrements complets. Dans un format réel, précise l’encodage du champ de nom et la convention de terminaison ou de remplissage ; un champ de nom fixe de 20 octets n’est pas automatiquement une chaîne C.
Vérifie la longueur complète et la signature d’un en-tête avant d’utiliser ses champs. Vérifie ensuite les nombres et les longueurs par rapport à des limites raisonnables et aux données disponibles avant d’allouer de la mémoire. Un nombre plausible ne suffit pas si des enregistrements ultérieurs manquent.
Lire la structure réelle du format
Certains fichiers PCM WAV ont un en-tête simple de 44 octets, avec la fréquence d’échantillonnage aux octets 24 à 27. Les octets 44 AC 00 00 se décodent en 44 100 échantillons par seconde. D’autres fichiers WAV contiennent des blocs supplémentaires : un lecteur général suit donc les identifiants et les tailles des blocs pour trouver le bloc fmt . Supposer que tous les fichiers ont la même disposition d’en-tête fixe peut conduire à lire un champ sans rapport comme fréquence.
Un format texte comme CSV évite les problèmes de taille des entiers, de boutisme et de bourrage des structures et se vérifie facilement. Il exige néanmoins une disposition des champs définie, des règles de mise entre guillemets et une analyse vérifiée. Choisis-le lorsque la lisibilité et l’échange comptent plus qu’une représentation binaire compacte.
Points clés
- Un format binaire portable définit la largeur, l’ordre des octets et le décalage de chaque champ.
- Les types entiers de largeur fixe ne suffisent pas à rendre portable une copie brute de structure.
- Convertis explicitement les octets vers la largeur non signée voulue avant le décalage de bits.
- Valide l’en-tête entier et limite les nombres avant de t’y fier.
- Suis la structure des blocs lorsqu’un format autorise des blocs supplémentaires.
- Un champ texte de largeur fixe exige un encodage et une convention de longueur explicites.
4Se déplacer à une position quelconque dans un fichier
Les positions dans un fichier rendent l’accès direct possible lorsque l’emplacement des enregistrements est connu. Pour calculer ces emplacements, il faut tenir compte des en-têtes, de la largeur des enregistrements et des indices commençant à zéro. Les positions dans les flux texte suivent des règles plus strictes, car la traduction peut modifier leur sens. Lorsqu’un flux permet à la fois la lecture et l’écriture, le positionnement contrôle aussi la validité du passage de l’une à l’autre. Mettre à jour un enregistrement combine donc un calcul d’emplacement et une suite d’opérations vérifiées qui préserve les données environnantes.
4.1 Obtenir et modifier la position dans le fichier avec ftell, fseek et rewind
Les lectures séquentielles parcourent les données dans l’ordre. L’accès direct permet à un programme d’atteindre un emplacement connu, comme un enregistrement dans un fichier volumineux. Le positionnement ne fonctionne que si le flux sous-jacent le prend en charge, et le sens d’une position diffère entre les flux binaires et les flux texte.
Obtenir et modifier la position
ftell(fp) renvoie une position de type long ou -1L en cas d’échec. Pour un fichier binaire, une position compte les octets depuis son début. fseek(fp, offset, whence) déplace la position par rapport à un point de référence choisi et renvoie 0 si la fonction réussit, une valeur non nulle en cas d’échec.
| Référence | Sens du décalage |
|---|---|
SEEK_SET | Depuis le début |
SEEK_CUR | Depuis la position courante |
SEEK_END | Depuis la fin |
Par exemple, fseek(fp, -4L, SEEK_END) demande à se placer aux quatre derniers octets d’un fichier binaire sur un système qui prend en charge les déplacements relatifs à la fin. Vérifie le résultat avant de lire. Une demande sur un tube ou un terminal, ou une demande de position avant le début d’un fichier ordinaire, peut échouer.
Calculer l’emplacement d’un enregistrement
Pour des enregistrements binaires de taille fixe sans en-tête, l’indice commençant à zéro multiplié par la largeur d’un enregistrement donne son décalage de départ. Avec des enregistrements de 24 octets, l’indice 3 commence à l’octet 72. Après la lecture de cet enregistrement entier, la position est 96.
long offset = 3L * (long)sizeof(struct record);
if (fseek(fp, offset, SEEK_SET) != 0) {
/* Handle the failed move before reading. */
}
Cet exemple suppose que le fichier a été écrit avec la même disposition de structure. Un format portable spécifié utilise sa largeur d’enregistrement définie. Tiens compte des octets d’en-tête lorsqu’ils sont présents. Le troisième enregistrement compté à partir de 1 a l’indice 2, et non 3. Pour les grands indices, valide la multiplication et assure-toi que le résultat est représentable dans un long avant le déplacement.
Sur les systèmes courants, se déplacer à la fin puis utiliser ftell permet de mesurer un fichier binaire : un fichier de 120 octets avec des enregistrements de 24 octets contient cinq enregistrements. Vérifie les deux appels et restaure ensuite la position. Le C standard n’exige pas que SEEK_END fonctionne de manière pertinente sur tous les flux binaires ; la méthode dépend donc de la prise en charge par le flux concerné.
Enregistrer les positions dans les flux texte sans calcul
Le mode texte peut traduire les fins de ligne. Une position renvoyée pour un flux texte sert à revenir à un endroit ; ce n’est pas un nombre auquel ajouter ou soustraire des valeurs. Un déplacement non nul dans un flux texte utilise une valeur renvoyée auparavant par ftell pour le même fichier, avec SEEK_SET. Un décalage nul est autorisé avec n’importe quel point de référence.
rewind(fp) revient au début et réinitialise les indicateurs de fin de fichier et d’erreur. La fonction ne renvoie aucun résultat ; utilise donc fseek(fp, 0L, SEEK_SET) et vérifie son résultat lorsque la réussite du déplacement doit être confirmée. Un fseek réussi réinitialise l’indicateur de fin de fichier et annule la remise de caractère par ungetc, mais laisse activé un indicateur d’erreur existant.
Conserver un jeton de position
fgetpos(fp, &pos) enregistre une position dans un fpos_t ; fsetpos(fp, &pos) la restaure. Vérifie si chaque fonction renvoie une valeur non nulle indiquant un échec. Traite fpos_t comme un jeton opaque, sans effectuer de calcul dessus. Il peut contenir des informations de position qui dépassent un simple nombre d’octets.
fseek et ftell utilisent long, qui est généralement sur 32 bits sous Windows et limite les positions représentables à environ 2 GiB. Un jeton de position évite de lier l’interface à long, mais la taille de fichier prise en charge dépend toujours de l’implémentation et de la configuration.
Points clés
- Vérifie si
fseekrenvoie une valeur non nulle et siftellrenvoie-1L. - Le décalage d’un enregistrement tient compte de l’en-tête et de tous les enregistrements précédents.
- Utilise systématiquement des indices commençant à zéro.
- Restaure les positions dans les flux texte avec des jetons enregistrés, sans calcul de décalage.
rewindréinitialise les deux indicateurs ; unfseekréussi réinitialise celui de fin de fichier.- Le positionnement exige un flux qui le prend en charge et des décalages représentables.
4.2 Mettre à jour en place des enregistrements de taille fixe
Un flux en lecture et écriture lit et écrit dans le même fichier. Utilise "r+b" pour préserver un fichier binaire existant tout en modifiant ses enregistrements. "w+b" efface immédiatement l’ancien fichier et les modes ajout imposent chaque écriture à la fin.
Rendre valides les passages entre lecture et écriture
Un flux en lecture et écriture suit deux règles de passage :
| Passage | Action nécessaire entre les opérations |
|---|---|
| De l’écriture à la lecture | Vider le tampon de sortie ou effectuer une opération de positionnement |
| De la lecture à l’écriture | Effectuer une opération de positionnement, sauf si la lecture a rencontré la fin du fichier |
Les fonctions de positionnement comprennent fseek, fsetpos et rewind. Vérifie les fonctions qui renvoient un résultat avant de continuer. Un passage sans l’action nécessaire constitue un comportement indéfini ; tu ne peux pas prévoir qu’il affectera seulement l’enregistrement suivant.
Mettre à jour un enregistrement complet
Supposons qu’un fichier sans en-tête contienne cinq enregistrements de 24 octets dans la même représentation que struct record. Pour modifier l’indice 3 :
- Ouvre avec
"r+b"et vérifie le pointeur. - Déplace-toi à l’octet 72 et vérifie que l’opération a réussi.
- Lis exactement un enregistrement complet.
- Fixe son membre
scoreà 99. - Reviens au début de l’enregistrement.
- Écris exactement un enregistrement et vérifie le résultat de la fermeture.
Les principales opérations intermédiaires sont :
if (fread(&rec, sizeof rec, 1, fp) != 1) {
/* Report the incomplete input, then clean up. */
goto cleanup;
}
rec.score = 99;
if (fseek(fp, -(long)sizeof rec, SEEK_CUR) != 0) {
/* Report the failed seek, then clean up. */
goto cleanup;
}
if (fwrite(&rec, sizeof rec, 1, fp) != 1) {
/* Report the failed write, then clean up. */
goto cleanup;
}
La fonction englobante fournit une étiquette cleanup qui ferme son flux et renvoie un échec sur ces branches. Après la lecture, la position est 96. Reculer de 24 octets sélectionne l’enregistrement d’origine et permet le passage de la lecture à l’écriture. Un remplacement réussi laisse le fichier à 120 octets avec cinq enregistrements. Restaurer une position de départ enregistrée est une autre manière valide d’effectuer la mise à jour.
Décider quand réécrire
Ajouter un enregistrement de 24 octets fait passer ce fichier à 144 octets. Se placer au début d’un flux "ab" ou "a+b" ne permet pas de transformer l’écriture suivante en écrasement : elle a toujours lieu à la fin courante.
Un remplacement en place doit tenir dans l’espace qu’il remplace. Passer de "Bo,7" à "Bo,9" convient. Écrire "Bo,12" sur "Bo,7\n" absorbe le caractère de fin de ligne et rattache le texte suivant à l’enregistrement. Pour agrandir ou réduire des enregistrements, écris un nouveau fichier corrigé. Le C standard ne possède pas de fonction de flux qui retire une plage d’octets du milieu d’un fichier. Pour supprimer un enregistrement, on peut aussi copier tous les enregistrements conservés ou marquer comme supprimé un enregistrement de taille fixe.
Préserver la possibilité de récupération lors du remplacement
Vérifie remove et rename ; les deux fonctions renvoient 0 si elles réussissent. Le fait que rename remplace ou non une destination existante est défini par l’implémentation. Linux et macOS prennent en charge le remplacement ; la bibliothèque C de Microsoft échoue lorsque la destination existe.
Une procédure de récupération portable écrit et ferme le nouveau fichier, renomme l’original sous un nom de sauvegarde distinct, puis renomme le nouveau fichier avec le nom d’origine. Si la mise en place échoue, conserve la sauvegarde pour pouvoir la restaurer et indique où elle se trouve. Ne supprime la sauvegarde qu’après la réussite de la mise en place. Cette suite d’opérations permet la récupération ; elle ne constitue ni une transaction atomique portable ni une garantie contre une coupure de courant.
Points clés
- Utilise
"r+b"pour mettre à jour un fichier existant sans le tronquer. - Respecte la règle de passage entre lecture et écriture même lorsque la position voulue semble évidente.
- Reviens au début d’un enregistrement après l’avoir lu et avant de le remplacer.
- Les écritures en mode ajout ont toujours lieu à la fin.
- Réécris les données lorsque leur longueur change.
- Vérifie chaque étape du remplacement et conserve un original récupérable.
5Détecter et signaler les erreurs de fichiers, puis rétablir le fonctionnement
Une opération sur un fichier peut échouer après une ouverture réussie, et une sortie mise en tampon peut échouer seulement à la fermeture. Les programmes fiables lisent les valeurs de retour, distinguent les données invalides des problèmes d’accès, préservent les informations d’erreur utiles et libèrent les ressources sur tous les chemins. Ces tâches vont ensemble : le diagnostic doit expliquer l’échec initial, tandis que le code de retour final doit aussi refléter les échecs détectés pendant la libération des ressources. Un programme de copie complet montre comment ces décisions s’intègrent au déroulement habituel d’un programme C.
5.1 Vérifier chaque résultat et distinguer la fin de fichier des erreurs
Un fichier peut s’ouvrir correctement et subir malgré tout un échec pendant la lecture, l’écriture, le positionnement ou la fermeture. Un programme robuste vérifie le résultat de l’opération réellement tentée. Il distingue une lecture achevée d’une entrée interrompue et des données mal formées d’un flux défaillant.
Connaître chaque signal d’échec
| Opération | Signal à traiter |
|---|---|
fopen, fgets | NULL |
fgetc, fputc, fflush, fclose | EOF |
fprintf | Un résultat négatif |
fputs | EOF |
fread, fwrite | Moins d’éléments complets que demandé |
fscanf | Moins d’affectations que prévu, ou EOF |
fseek, fgetpos, fsetpos | Un résultat non nul |
ftell | -1L |
rewind, clearerr et perror ne renvoient aucune valeur. Si la réussite d’un retour au début doit être vérifiée, utilise fseek au lieu de compter sur un résultat de rewind.
Examiner le flux après l’arrêt d’une lecture
Le flux conserve des indicateurs distincts de fin de fichier et d’erreur. feof(fp) teste le premier ; ferror(fp) teste le second. Chaque fonction renvoie une valeur non nulle si son indicateur est activé.
while (fgets(line, sizeof line, fp) != NULL) {
/* Process successful input. */
}
if (ferror(fp)) {
fprintf(stderr, "Input could not be completed\n");
/* Return failure after cleanup. */
}
La valeur renvoyée par fgets ne suffit pas à distinguer les deux causes d’arrêt. De même, fgetc renvoie EOF et fread renvoie un nombre inférieur à celui demandé aussi bien en fin de fichier qu’en cas d’échec de lecture. Ne teste pas feof avant la lecture pour prédire s’il reste des données.
Les indicateurs restent activés. clearerr les réinitialise tous les deux, tout comme rewind. Un fseek ou un fsetpos réussi réinitialise l’indicateur de fin de fichier, mais pas un indicateur d’erreur existant. Réinitialiser un indicateur revient à en prendre acte ; cela ne reconnecte pas un périphérique retiré et ne répare pas un fichier endommagé. Ne réessaie qu’après avoir traité la cause.
Distinguer les données invalides d’un échec d’accès
Si fscanf(fp, "%d", &value) renvoie 0 sur "abc", la conversion a échoué avant toute affectation. Cela n’exige ni fin de fichier ni erreur de lecture. Signale un champ invalide, de préférence avec un numéro de ligne. Un message concernant le disque décrirait le mauvais problème.
Si un en-tête obligatoire est lu comme un seul élément et que fread renvoie 0, l’en-tête est incomplet. N’examine pas cet objet partiellement rempli. Si ferror est activé, signale une erreur d’entrée ; si le fichier s’est terminé, signale des données tronquées. Un fichier vide et un en-tête incomplet peuvent produire le même nombre d’éléments : c’est donc le format attendu qui impose la présence de l’en-tête.
Détecter les échecs tardifs en sortie
Un disque peut se remplir après l’ouverture de la sortie par le programme. Les écritures mises en tampon peuvent sembler réussir jusqu’à ce que fflush ou fclose transfère réellement les octets en attente. Vérifie la fermeture finale et fais en sorte qu’un échec à cette étape transforme en échec une tâche qui aurait autrement réussi. Ne ferme pas à nouveau le même flux ensuite.
Dans un terminal, Ctrl+D au début d’une ligne sous Linux ou macOS, ou Ctrl+Z puis Entrée sous Windows, signale généralement la fin de l’entrée. clearerr(stdin) réinitialise l’indicateur obtenu si le programme doit faire une nouvelle tentative. L’action dans le terminal et une erreur de lecture restent des causes différentes.
Points clés
- Vérifie chaque fonction selon sa propre valeur de retour documentée.
- Lis d’abord, puis utilise les indicateurs du flux pour déterminer la raison de l’arrêt.
- Une incompatibilité de format indique des données invalides, pas nécessairement une erreur de flux.
- Rejette les en-têtes et les enregistrements obligatoires incomplets.
- Une erreur tardive à la fermeture de la sortie doit entraîner l’échec de la tâche.
5.2 Expliquer les échecs avec errno, perror et strerror
Une valeur de retour t’indique qu’une opération a échoué. Un code d’erreur peut aider à comprendre pourquoi. Utilise errno uniquement dans le contexte du comportement documenté de l’opération et préserve sa valeur avant que des appels sans rapport à la bibliothèque puissent la modifier.
Laisser l’opération établir l’échec
errno est une expression int modifiable de <errno.h>, dont la durée de stockage est propre à chaque fil d’exécution en C11. Sa valeur initiale est zéro. Les appels à la bibliothèque ne la remettent pas à zéro et un appel réussi peut laisser ou affecter une valeur non nulle. Tester errno après un fopen réussi ne permet donc pas de conclure que l’ouverture a échoué.
Sur les systèmes POSIX, un fopen échoué affecte un code d’erreur. La bibliothèque C de Microsoft fournit aussi des codes d’erreur de fichier. Le C standard n’exige pas que fopen affecte une valeur à errno. Pour signaler l’erreur de façon portable, on peut le remettre à zéro avant l’ouverture et utiliser un message général si aucun code n’a été fourni :
errno = 0;
FILE *fp = fopen(name, "r");
if (fp == NULL) {
int saved = errno;
if (saved != 0)
fprintf(stderr, "Cannot open %s: %s\n",
name, strerror(saved));
else
fprintf(stderr, "Cannot open %s\n", name);
return EXIT_FAILURE;
}
Cet extrait exige aussi <stdio.h>, <stdlib.h> et <string.h>. Enregistrer immédiatement le code empêche les appels ultérieurs de signalement ou de libération des ressources de remplacer la raison d’origine. Un code enregistré reste utile même si le message final est affiché bien plus tard.
Choisir une fonction de message
perror(label) écrit dans stderr la chaîne indiquée, deux-points et une espace, le message d’erreur courant, puis un caractère de fin de ligne. Un message typique pour un fichier absent est "missing.txt: No such file or directory" ; sa formulation exacte dépend du système.
strerror(code) renvoie le message de la bibliothèque correspondant au code fourni ; il convient donc à un diagnostic personnalisé qui indique le programme, l’opération et le fichier. Ne modifie pas la chaîne renvoyée. Utilise strerror(saved) après la libération des ressources au lieu de demander la nouvelle valeur de errno.
Le C définit EDOM, ERANGE et EILSEQ. Les codes de fichier courants comme ENOENT, EACCES, EEXIST et ENOSPC sont fournis par POSIX et par des bibliothèques C largement disponibles. Adapte ton code à l’interface et à la plateforme visées. Ne suppose pas que les valeurs numériques des codes ou le texte anglais exact des messages sont universels.
Gérer une valeur de retour ambiguë
Pour certaines fonctions, le résultat seul ne permet pas de distinguer une réussite d’une erreur de dépassement de plage. strtol peut renvoyer LONG_MAX comme nombre valide ou comme résultat d’un débordement. Remets errno à zéro avant la conversion, puis examine le code de dépassement de plage documenté :
errno = 0;
char *end;
long value = strtol(text, &end, 10);
if (end == text) {
/* No digits were converted. */
} else if (errno == ERANGE) {
/* The value is outside the long range. */
} else {
/* Validate trailing characters and the target range. */
}
Un diagnostic utile donne à l’utilisateur des éléments pour agir. Indique le fichier et l’action tentée ; conserve la raison donnée par le système lorsqu’elle est disponible. Envoie le diagnostic vers stderr, en laissant stdout disponible pour les données de résultat valides.
Points clés
- Utilise le résultat de la fonction pour établir l’échec avant d’interpréter
errno. - Enregistre
errnoimmédiatement avant les appels de signalement ou de libération des ressources. perrorutilise la valeur courante deerrno;strerroraccepte un code enregistré.- Remets
errnoà zéro avantstrtolet vérifieERANGE. - Indique le fichier et l’action tentée dans un diagnostic.
5.3 Libérer les ressources et indiquer le résultat de l’opération
La gestion des erreurs n’est complète que lorsque les ressources sont libérées et que le programme indique le résultat réel. Prévois la propriété des ressources lorsque tu ouvres un flux et fais en sorte que tous les chemins ultérieurs respectent cette répartition.
Associer une fermeture à chaque ouverture
Si l’ouverture de l’entrée échoue, il n’y a aucun flux à fermer. Si l’ouverture de la sortie échoue après la réussite de celle de l’entrée, ferme l’entrée. Si la copie échoue après l’ouverture des deux flux, ferme-les tous les deux, vérifie la fermeture de la sortie et conserve un code de retour indiquant l’échec. Fermer deux fois un pointeur n’apporte aucune protection supplémentaire : cela utilise un flux déjà fermé.
Le code avec retours anticipés ferme généralement les ressources dans l’ordre inverse de leur acquisition. Une étiquette commune de libération des ressources est utile lorsque plusieurs chemins d’échec exigent les mêmes opérations. Initialise les pointeurs à NULL, conserve un code d’échec par défaut et ne fixe la réussite qu’une fois la phase de traitement terminée.
Le programme complet suivant copie des fichiers d’entrée et de sortie distincts en mode binaire. Il utilise des messages généraux, car le C standard n’exige pas que chaque échec d’une fonction de stdio fournisse une valeur dans errno.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *in = NULL, *out = NULL;
int status = EXIT_FAILURE;
int output_acquired = 0;
unsigned char buf[512];
size_t n;
if (argc != 3) {
fprintf(stderr, "Usage: %s input output\n", argv[0]);
return EXIT_FAILURE;
}
in = fopen(argv[1], "rb");
if (in == NULL) {
fprintf(stderr, "Cannot open input: %s\n", argv[1]);
goto cleanup;
}
out = fopen(argv[2], "wb");
if (out == NULL) {
fprintf(stderr, "Cannot open output: %s\n", argv[2]);
goto cleanup;
}
output_acquired = 1;
while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
if (fwrite(buf, 1, n, out) != n) {
fprintf(stderr, "Write failed: %s\n", argv[2]);
goto cleanup;
}
}
if (ferror(in)) {
fprintf(stderr, "Read failed: %s\n", argv[1]);
goto cleanup;
}
status = EXIT_SUCCESS;
cleanup:
if (out != NULL && fclose(out) == EOF) {
fprintf(stderr, "Close failed: %s\n", argv[2]);
status = EXIT_FAILURE;
}
if (in != NULL && fclose(in) == EOF) {
fprintf(stderr, "Close failed: %s\n", argv[1]);
status = EXIT_FAILURE;
}
if (output_acquired && status != EXIT_SUCCESS) {
if (remove(argv[2]) != 0)
fprintf(stderr, "Cannot remove incomplete output: %s\n",
argv[2]);
}
return status;
}
La boucle d’entrée ne traite que les octets effectivement lus. Une écriture incomplète entraîne un saut vers la libération des ressources ; une erreur d’entrée est vérifiée après la boucle. La fermeture de la sortie peut encore transformer une réussite en échec. La suppression n’est tentée que si cette exécution a réussi à ouvrir la sortie : un échec d’ouverture ne déclenche donc pas la suppression d’un fichier sans rapport. L’exigence de fichiers distincts compte : "wb" effacerait l’entrée si les deux noms désignaient le même fichier.
Préserver les données existantes importantes
L’ouverture directe de la sortie ne permet pas d’annuler une troncature. Pour remplacer des données importantes, écris d’abord sous un nom temporaire distinct. Vérifie chaque écriture et la fermeture finale avant de renommer les fichiers. Conserve l’original sous un nom de sauvegarde jusqu’à la mise en place du nouveau fichier ; vérifie chaque renommage et chaque suppression. Si la mise en place échoue, indique l’emplacement du fichier récupérable au lieu de le supprimer.
Une fonction auxiliaire doit fermer ce qu’elle a ouvert et renvoyer un résultat de réussite ou d’échec à sa fonction appelante. Celle-ci peut décider de réessayer ou de quitter le programme. Renvoyer EXIT_FAILURE après toute étape incomplète permet à un script de s’arrêter avant une action qui en dépend, comme la suppression de l’original après une sauvegarde.
Points clés
- Initialise la gestion de la propriété des flux et conserve un code d’échec par défaut.
- Ferme chaque flux ouvert avec succès exactement une fois sur chaque chemin.
- Fais en sorte qu’un échec de fermeture modifie le code de retour final.
- Ne supprime une sortie incomplète que si cette exécution l’a créée ou ouverte.
- Écris les fichiers de remplacement séparément et préserve l’original jusqu’à la réussite de leur mise en place.
- Les fonctions auxiliaires signalent les échecs à leurs fonctions appelantes pour qu’elles puissent choisir comment rétablir le fonctionnement.
Entrées et sorties de fichiers en C : exemples
1Ouvrir un flux sans perdre les données existantes
12 étapes
- 1IntroductionDéterminer ce qui doit être conservé
Un programme s’apprête à enregistrer des résultats. Avant toute ouverture, détermine si les anciennes données doivent être conservées et si le fichier contient des lignes lisibles ou des octets à préserver exactement. Ces choix déterminent le mode, et un mauvais choix peut effacer les anciennes données.
Tu vas suivre une écriture depuis le texte du programme jusqu’au flux (le canal de la bibliothèque vers un fichier ou un terminal), puis choisir où envoyer les résultats normaux et les diagnostics (les flux standard). L’ouverture est déjà une opération sur le fichier : cette décision précède donc la première écriture.
- 2ExplicationAccéder aux données par un flux
Un flux est le canal de la bibliothèque standard vers un fichier, un terminal ou un tube. Conserve son pointeur sous forme d’un
FILE *de<stdio.h>et passe-le à des fonctions commefprintf.L’objet de la bibliothèque mémorise le tampon, la position et les indicateurs d’état. Tu ne modifies pas ses champs. La position dans un fichier avance à mesure que les données sont traitées ; un terminal ou un tube ne peut pas être traité comme un fichier ordinaire pour le positionnement.
- 3ExempleSuivre les fins de ligne jusqu’aux octets stockés
Écrire
"a\nb\nc\n"fournit trois lettres et trois caractères de fin de ligne. Sous Linux ou macOS, le fichier texte contient six octets. Sous Windows, chaque caractère de fin de ligne devient CR LF, ce qui donne neuf octets stockés.La lecture de ce fichier Windows en mode texte sous Windows restitue six caractères. La lecture en mode binaire donne accès aux neuf octets. Le texte du programme et la suite d’octets stockée sont deux représentations des mêmes lignes.
- 4LienChoisir un mode pour une image
Une suite d’octets dans une image compressée peut contenir des valeurs que le mode texte traduit. Ajouter
bsélectionne le mode binaire et préserve ces valeurs.Cela explique pourquoi un lecteur d’images qui fonctionne avec
"r"sous Linux peut échouer sous Windows. Il doit utiliser"rb"parce qu’il traite une suite d’octets définie, et non des lignes que la bibliothèque doit traduire. - 5DéfiVérifier un nombre de caractères
Sous Windows, une écriture en mode texte stocke
"m\nn\n". Combien d’octets le fichier obtenu contient-il, et pourquoi ?---reveal---
Il contient six octets : deux lettres et deux paires CR LF. Les quatre caractères fournis par le programme occupent plus d’espace, car chaque caractère de fin de ligne devient deux octets stockés. En mode binaire, ces quatre mêmes octets fournis seraient écrits sans cette traduction.
- 6ExplicationChoisir ce qui doit être préservé avant l’accès
Pour un fichier existant,
"r"permet la lecture,"w"efface le contenu et permet l’écriture, et"a"conserve les données et ajoute à la fin. Un+permet à la fois l’entrée et la sortie.Utilise
"r+"pour préserver un fichier existant lors des mises à jour."w+"l’efface malgré tout. En C11,"wx"échoue si le fichier existe, ce qui est utile lorsqu’une destination existante doit être protégée. - 7ConseilAcquérir et libérer un flux
Après
FILE *fp = fopen(name, "r");, testefp == NULLavant toute opération sur le flux. En cas d’échec, aucun flux n’est fourni à traiter ou à fermer.En cas de réussite, le programme possède un flux qui exige un
fclose. Vérifie aussi cette fermeture. Le flux est terminé après l’appel, même si la fermeture échoue ; tenter de le fermer à nouveau utilise un flux qui n’est plus valide. - 8DéfiProtéger le journal existant
Un journal existant doit conserver ses entrées et une nouvelle ligne doit y être ajoutée. Une personne choisit
"w"parce que la tâche consiste à écrire. Quel mode faut-il utiliser, et à quel moment"w"détruirait-il les anciennes entrées ?---reveal---
Utilise
"a". Le mode"w"détruit le contenu existant dès que l’ouverture réussit, avant même une écriture. Le choix doit protéger le journal dès l’ouverture, et pas seulement pendant le code de traitement ultérieur. - 9ExplicationSéparer les résultats des explications
Les flux déjà ouverts sont
stdinpour l’entrée,stdoutpour les résultats etstderrpour les diagnostics. Une fonction qui accepteFILE *outpeut écrire la même présentation dans un fichier ou dansstdout.Un interpréteur de commandes peut rediriger la sortie standard vers un fichier ou l’envoyer par un tube à un autre programme. Garde les diagnostics sur
stderrpour qu’un résultat lisible par une machine ne reçoive pas de messages d’erreur entre ses lignes de données. - 10Point cléFaire apparaître le texte mis en tampon
Les sorties peuvent attendre dans un tampon en mémoire. La sortie standard vers un terminal est généralement mise en tampon par ligne ; la sortie redirigée est généralement entièrement mise en tampon. La sortie d’erreur standard n’est pas entièrement mise en tampon.
Une invite sans caractère de fin de ligne peut exiger un appel à
fflush(stdout)dont le résultat est vérifié avant le début de l’entrée. Vider le tampon n’élimine pas les entrées. Pour ignorer une ligne d’entrée indésirable, lis les caractères jusqu’à sa fin de ligne ou à la fin du fichier. - 11DéfiSuivre la sortie d’un filtre
Un filtre lit l’entrée standard, écrit les résultats sur la sortie standard et écrit les erreurs sur la sortie d’erreur standard. Il est exécuté avec
filter < raw.txt > clean.txt. Où un message signalant un enregistrement rejeté doit-il apparaître, et quel code de retour le programme doit-il renvoyer s’il ne peut pas terminer la tâche ?---reveal---
Le diagnostic va vers la destination d’erreur héritée, généralement le terminal. Renvoie
EXIT_FAILURE. Le fichier de résultats reste séparé du message et l’interpréteur de commandes peut détecter l’échec. - 12RécapitulatifGérer délibérément le cycle de vie d’un flux
Avant l’ouverture, choisis ce qui doit être préservé et le mode texte ou binaire. Vérifie que l’ouverture a produit un flux, ne traite les données qu’à l’aide de pointeurs valides et ferme une fois chaque flux dont tu es responsable.
Les flux standard permettent à l’interpréteur de commandes de fournir les connexions. Sépare les résultats des diagnostics et renvoie un code qui décrit le résultat de la tâche. Ces choix permettent au même petit programme de fonctionner de manière interactive, avec des fichiers ou dans une chaîne de tubes.
2Lire un enregistrement texte et valider son contenu
15 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionLire au bon niveau
- 2ExplicationDistinguer un caractère de EOF
- 3ExempleNe compter qu’une lecture réussie
- 4DéfiInclure la dernière ligne non terminée
- 5ExempleÉcrire selon une présentation contrôlée
- 6ConseilRéserver le caractère nul de fin de chaîne
- 7ExplicationUtiliser le nombre d’affectations réussies
- 8DéfiFormater un nom dans un espace limité
- 9ExplicationLire une ligne dans une zone de capacité connue
- 10ExempleSuivre une ligne sur deux lectures
- 11ConseilSupprimer la fin de ligne sans supprimer de données
- 12ExplicationAnalyser la ligne déjà lue
- 13DéfiAccepter une ligne qui tient exactement
- 14DéfiRejeter un préfixe suivi d’une partie invalide
- 15RécapitulatifSéparer la lecture de l’interprétation
3Transférer des octets et définir leur sens
12 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDistinguer les octets des valeurs
- 2ExplicationChoisir ce que compte la valeur de retour
- 3ExempleSuivre le dernier bloc incomplet
- 4Point cléDistinguer un enregistrement d’un bloc d’octets
- 5DéfiUtiliser le nombre effectivement lu
- 6ExplicationNe pas laisser le compilateur concevoir le format
- 7ExempleDécoder une valeur petit-boutiste
- 8ExempleTrouver un enregistrement à partir de sa disposition
- 9DéfiVérifier la quantité de données déclarée
- 10LienSuivre la structure autorisée par le format
- 11DéfiExiger un champ complet avant de le décoder
- 12RécapitulatifFaire correspondre le transfert et le format
4Trouver un enregistrement et le remplacer en toute sécurité
13 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionAccéder directement aux données nécessaires
- 2ExplicationChoisir un point de référence
- 3ExempleTrouver l’enregistrement d’indice 3
- 4ConseilRestaurer les positions dans les flux texte à l’aide de jetons
- 5DéfiTrouver le troisième enregistrement
- 6ExplicationPréserver le fichier existant
- 7ExempleRevenir au début de l’enregistrement
- 8Point cléTerminer le remplacement
- 9DéfiChoisir à la fois le mode et le déplacement
- 10LienRéécrire lorsqu’un enregistrement s’allonge
- 11ConseilPréserver la possibilité de récupération lors de la mise en place
- 12DéfiInterpréter un ajout effectué
- 13RécapitulatifLe positionnement fait partie d’une mise à jour valide
5Prendre en compte l’échec lors du signalement et de la libération des ressources
12 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionLa réussite comprend la fermeture finale
- 2ExplicationLire le résultat de chaque fonction
- 3ExplicationExpliquer pourquoi l’entrée s’est arrêtée
- 4DéfiRejeter un en-tête tronqué
- 5ExplicationEnregistrer la raison d’origine
- 6ExempleAfficher un message à partir du code enregistré
- 7DéfiChoisir la bonne source pour le diagnostic
- 8ExplicationSuivre les flux acquis
- 9ExempleLaisser la libération des ressources modifier le résultat
- 10DéfiDéterminer la prochaine action d’un script
- 11Point cléConserver l’original après un échec de renommage
- 12RécapitulatifRenvoyer le résultat de toute la tâche
Entrées et sorties de fichiers en C : QCM
Série 1 : Gérer les frontières du texte et les dispositions binaires10 Questions Pratiques
Question 1 sur 10
/work/run et ouvre "data/items.txt". Quel chemin est résolu ?Afficher la réponseMasquer la réponse
data/items.txt à /work/run donne /work/run/data/items.txt. L’emplacement du fichier source ou de l’exécutable ne détermine pas cette recherche : changer le dossier depuis lequel le programme est lancé peut donc changer le fichier qu’il ouvre.Question 2 sur 10
producer | consumer > result.txt d’un interpréteur de commandes, où va par défaut la sortie d’erreur standard du producteur ?Afficher la réponseMasquer la réponse
result.txt ne redirige pas aussi les diagnostics du producteur.Question 3 sur 10
fread(buf, 1, 600, in). Quelles tailles les écritures réussies doivent-elles utiliser ?Afficher la réponseMasquer la réponse
Question 4 sur 10
char name[8]; reçoit snprintf(name, sizeof name, "part-%d", 2468), qui renvoie 9. Que doit conclure le programme ?Afficher la réponseMasquer la réponse
"part-2468" exige neuf caractères plus un caractère nul de fin de chaîne, ce qui dépasse la capacité de huit octets. snprintf limite ce qu’il stocke et indique la longueur complète nécessaire ; une valeur de retour non négative au moins égale à la capacité signale donc une troncature. Le 9 indiqué n’est pas le nombre de caractères réellement stockés.Question 5 sur 10
"cedars\nmaplesx". Il appelle à plusieurs reprises fgets(buf, 8, fp). Quelles frontières entre les enregistrements doit-il reconnaître ?Afficher la réponseMasquer la réponse
Question 6 sur 10
"north\nsouth\neast". Combien de lignes et de caractères de fin de ligne contient-elle ?Afficher la réponseMasquer la réponse
"east" forme une troisième ligne. Un compteur qui ne s’incrémente que pour les caractères de fin de ligne indiquerait 2 et manquerait cette dernière ligne. Un compteur de lignes robuste ajoute un lorsque le dernier caractère lu avec succès n’est pas un caractère de fin de ligne.Question 7 sur 10
uint32_t, mais diffèrent par l’ordre des octets et le bourrage des structures. Un programme écrit struct { char kind; uint32_t count; } à l’état brut avec un seul fwrite. Quelle modification rend la représentation indépendante de ces deux différences ?Afficher la réponseMasquer la réponse
Question 8 sur 10
long p = ftell(fp); et vérifiée. Après d’autres lectures, quel appel valide permet d’y revenir ?Afficher la réponseMasquer la réponse
SEEK_SET pour le même fichier. La traiter comme une distance en octets depuis l’emplacement courant peut conduire à mal interpréter la valeur enregistrée, surtout lorsqu’une traduction du texte a lieu. Ajouter un à cette valeur crée de même une position calculée que les règles des flux texte n’autorisent pas.Question 9 sur 10
"r+b" se place à l’octet 40 et lit un enregistrement complet sans atteindre EOF. Un champ est modifié. Quelle opération avant l’écriture permet à la fois le passage à l’écriture et la sélection du même enregistrement ?Afficher la réponseMasquer la réponse
Question 10 sur 10
Afficher la réponseMasquer la réponse
errno immédiatement après l’échec signalé, avant que la libération des ressources puisse le modifier. Le message ultérieur peut utiliser strerror(saved) pour décrire le code d’origine. Lire la valeur courante de errno seulement après la fermeture d’un autre flux peut conduire à signaler l’état de cette opération ultérieure au lieu de l’échec que l’utilisateur doit comprendre.Série 2 : Choisir les flux et traiter une entrée complète10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
fgets réussit à lire la dernière ligne, qui contient "maple" sans caractère de fin de ligne. Que laisse line[strlen(line) - 1] = '\0'; ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
0xFF et contient d’autres données. Pourquoi char c; while ((c = fgetc(fp)) != EOF) peut-il s’arrêter immédiatement ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
char tag[14]; int count;, quel appel lit sans danger un mot et un entier dans ces objets ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
fwrite(a, 4, 7, fp) réussi écrit tous les éléments demandés. Que renvoie-t-il ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
07 02 00 00. Quelle valeur représente-t-il ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
fread(&h, 16, 1, fp). La fonction renvoie 0, ferror(fp) vaut zéro et feof(fp) est non nul. Comment le lecteur doit-il procéder ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 3 : Mettre à jour des enregistrements et préserver des résultats fiables10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
"x\ny\n" est écrit en mode texte. Combien d’octets sont stockés ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
"64km" est passée à strtol après la remise à zéro de errno. La valeur renvoyée est 64, errno reste à 0 et end pointe sur k. Le champ doit contenir un entier seul, éventuellement suivi de caractères blancs. Quelle décision convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
fread(b, 16, 1, fp) avec un tableau de 16 octets. Que renvoie le second appel et comment son élément peut-il être utilisé ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
"18 pear 26". Après un appel réussi à fscanf(fp, "%d", &n), le même appel renvoie deux fois 0. Pourquoi n’a-t-il pas atteint 26 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
"r+b", se place à l’octet 38 et lit un enregistrement complet sans atteindre EOF. Il modifie un champ. Quelle opération sélectionne ensuite le même enregistrement et permet de l’écrire pour le remplacer ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 4 : Diagnostiquer les échecs dans un traitement complet de fichiers10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
"ready" échoue alors que les lettres visibles correspondent. Quel caractère conservé explique cela ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
totals.txt à l’aide d’un interpréteur de commandes. Quel opérateur de redirection faut-il utiliser ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
"a+b", un programme se place à l’octet 12, lit un enregistrement, remplace son score par 25, revient à l’octet 12 et écrit l’enregistrement. Tous les appels réussissent. Quels scores contiennent ensuite le deuxième et le dernier enregistrement ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
char buf[8], les lectures renvoient "8642kg\n", puis "1234567" ; la lecture suivante, dont le résultat est vérifié, confirme une fin de fichier normale. strtol trouve 8642 suivi de kg dans le premier enregistrement et convertit tous les chiffres du second, sans erreur de dépassement de plage. Quels enregistrements sont valides ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
"a\nb". Un programme utilise int c; size_t n = 0, lines = 0; while (c = fgetc(in) != EOF) { ++n; if (c == '\n') ++lines; }. Quels totaux obtient-on, et quelle correction permet de compter correctement les lignes ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Tu bloques sur ton propre exercice ? Aide aux Devoirs
Mots-Clés
A
Accès direct
Analyse d’une ligne
B
Bourrage de structure
char suivi d’un int peut occuper huit octets même si leurs tailles totalisent cinq octets.Boutisme
C
Caractère nul de fin de chaîne
fgets est autorisé à lire.Chemin de nettoyage
clearerr
Code de retour
&& ne doit pas s’exécuter après une copie de fichier incomplète.Copie par blocs
Création exclusive
"wx" empêche qu’un rapport existant soit effacé lors de l’ouverture.E
En-tête de fichier
Entrée standard
stdin, par lequel un programme reçoit normalement son entrée principale.< values.txt, un filtre lit les données d’un fichier par stdin au lieu du clavier.EOF
int pour qu’un octet réel ne soit pas confondu avec ce marqueur.ERANGE
errno à zéro avant strtol pour ne pas confondre une ancienne erreur de dépassement de plage avec une nouvelle.errno
É
Échec de correspondance
"oak" peut renvoyer 0 alors que les indicateurs de fin de fichier et d’erreur du flux restent désactivés.Élément incomplet
fread.F
fclose
EOF.fclose(fp), même en cas d’erreur, ce flux ne peut plus être utilisé.fgetc
int, ou renvoie EOF.fgetc a renvoyé un caractère avec succès.fgets
Flux
Flux en lecture et écriture
+, qui autorise l’entrée et la sortie selon des règles de passage de l’une à l’autre."r+b" le préserve pour un accès en lecture et écriture.fopen
NULL.fgetc ou à fclose.fpos_t
fgetpos et fsetpos pour enregistrer et restaurer toutes les informations nécessaires sur la position dans un fichier.fputc
EOF en cas d’échec.fputc après avoir transformé le caractère lu.fread
fseek
ftell
long et renvoie -1L en cas d’échec ; une position dans un flux texte doit être traitée comme un emplacement enregistré.fwrite
I
Indicateur d’erreur
NULL par fgets, ferror peut distinguer un échec d’accès d’une fin normale.Indicateur de fin de fichier
L
Largeur de champ
%23s laisse de la place pour un caractère nul de fin de chaîne dans un tableau de caractères de 24 octets.M
Mise à jour en place
Mise en tampon
Mise entre guillemets des champs CSV
Mode ajout
"a+b" peut sélectionner une position de lecture, mais ne peut pas rediriger l’écriture suivante.Mode binaire
"rb" pour que la traduction de texte ne puisse pas modifier ses octets compressés.Mode d’ouverture
fopen les accès autorisés et précise si le contenu existant est conservé ou effacé."a" préserve les entrées précédentes d’un journal et place chaque nouvelle écriture à la fin.Mode texte
N
Nombre d’affectations réussies
fscanf n’est complet que si le nombre d’affectations réussies renvoyé est 2.O
Ordre gros-boutiste
00 00 01 02 dans un champ gros-boutiste de 32 bits.Ordre petit-boutiste
02 01 00 00 représentent 258 dans un champ petit-boutiste de 32 bits.P
perror
errno sur la sortie d’erreur standard, suivis d’un caractère de fin de ligne.Pointeur de fin de conversion
strtol indique le premier caractère après le préfixe numérique accepté par la conversion."86cm", le pointeur atteint le c, ce qui permet de rejeter les caractères restants dans un champ entier.Pointeur FILE
FILE * qui donne aux fonctions de la bibliothèque accès à un flux et à son état enregistré.fp à fgetc après avoir vérifié que l’ouverture a renvoyé un pointeur de flux valide.Position dans le fichier
Propriété des ressources
R
Redirection
2> peut enregistrer les messages de diagnostic d’un programme dans un fichier distinct.Remise d’un caractère dans le flux
ungetc pour le laisser à l’étape suivante.Remplacement avec possibilité de récupération
rename
Répertoire de travail courant
"data/input.txt".S
Signature de fichier
snprintf
Sortie d’erreur standard
stderr, utilisé pour les diagnostics indépendamment du flux des résultats normaux d’un programme.stderr tandis que les données valides vont vers stdout.Sortie standard
stdout, utilisé pour les résultats normaux et les autres sorties principales d’un programme.stdout d’un convertisseur vers l’entrée standard d’un autre programme.Spécification de conversion
%lf exige une destination double *, tandis que %f exige une destination float *.strcspn
"\r\n" comme ensemble à exclure permet de trouver une fin de ligne sans supprimer de données utiles à la fin.strerror
errno.T
Tube
Type entier de largeur fixe
uint32_t exige toujours un encodage explicite des octets pour rendre portable un fichier d’échange.À propos de cette unité
Crée ton propre Matériel d'Étude
Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.