--- title: "Lecture/écriture de fichiers" date: "2023-12-14" --- # Les fichier en C * Un fichier en C est représenté par un pointeur de fichier. ```C #include <stdio.h> FILE *fp; ``` * `FILE *`{.C} est une structure de donnée *opaque* contenant les informations sur l'état du fichier. * Il est manipulé à l'aide de fonctions dédiées. * Le pointeur de fichier est toujours passé *par copie*. # Manipulations de fichier * Pour lire/écrire dans un fichier il faut toujours effectuer trois étapes: 1. Ouvrir le fichier (`fopen()`{.C}). 2. Écrire/lire dans le fichier (`fgets()`{.C}, `fputs()`{.C}, `fread()`{.C}, `fwrite()`{.C}, ...). 3. Fermer le fichier (`fclose()`{.C}). * Nous allons voir brièvement ces trois étapes. # Ouverture d'un fichier * L'ouverture d'un fichier se fait avec la fonction `fopen()`{.C} ```C FILE *fp = fopen(filename, mode); ``` * `filename`{.C} est une chaîne de caractères (incluant le chemin). * `mode`{.C} est le mode d'ouverture (`"r"`{.C}, `"w"`{.C}, ... voir `man 3 fopen`{.bash}) qui est une chaîne de caractères. * Si l'ouverture échoue (pas la bonne permission, ou n'existe pas) `fopen()`{.C} retourne `0`. * **Toujours** tester le retour de `fopen()`{.C} ```C if (NULL == fp) { fprintf(stderr, "Can't open output file %s!\n", filename); // affiche dans le canal d'erreur exit(EXIT_FAILURE); } ``` # Fermeture d'un fichier * Il faut **toujours** fermer un fichier à l'aide de `fclose()`{.C} ```C FILE *fp = fopen("mon_fichier", "w"); // écritures diverses fclose(fp); ``` * Les données sont transférées dans une mémoire tampon, puis dans le disques. * Si la mémoire tampon est pleine, le fichier est fermé, ... les données sont écrites sur le disque. * Si la mémoire tampon contient encore des données à la fin du programme les données sont **perdues**. # Lecture d'un fichier (1/2) ```C char *fgets(char *s, int size, FILE *stream) ``` * Lit une ligne de taille d'au plus `size-1` et la stocke dans `s`, depuis `stream`. * Retourne `s` ou `NULL` si échoue. ```C FILE *fp = fopen("text.txt", "r"); char buffer[100]; fgets(buffer, 37, fp); // lit 36 caractères au plus et les écrit dans buffer // s'arrête si rencontre EOF, ou "\n". // ajoute un "\0" terminal fclose(fp); ``` # Lecture d'un fichier (2/2) ```C size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) ``` * Lit `nmemb` éléments de taille `size` octets et les écrit à l'adresse `ptr` dans le fichier `stream`. * Retourne le nombre d'éléments lus. ```C FILE *fp = fopen("doubles.bin", "rb"); double buffer[100]; size_t num = fread(buffer, sizeof(double), 4, fp); // lit 4 double, se trouvant dans le fichier fp au // format binaire et les écrit dans buffer, puis // retourne 4 fclose(fp); ``` # Écriture dans un fichier (1/2) ```C int fprintf(FILE *stream, const char *format, ...) ``` * Écrit la chaîne de caractères `format` dans le fichier stream. * `format` a la même syntaxe que pour `printf()`. * Retourne le nombre de caractères écrit sans le `\0` terminal(si réussite). ```C FILE *fp = fopen("text.txt", "w"); fprintf(fp, "Hello world! We are in %d\n", 2020); // Écrit "Hello world! We are in 2020" // dans le fichier fp fclose(fp); ``` # Écriture dans un fichier (2/2) ```C size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) ``` * Écrit `nmemb` éléments de taille `size` octets se trouvant à l'adresse `ptr` dans le fichier `stream`. * Retourne le nombre d'éléments écrits. ```C FILE *fp = fopen("doubles.bin", "wb"); double buffer[] = {1.0, 2.0, 3.0, 7.0}; size_t num = fwrite(buffer, sizeof(double), 4, fp); // écrit 4 double, se trouvant à l'adresse // buffer dans le fichier fp au format binaire // retourne 4 fclose(fp); ``` # Les pointeurs de fichiers spéciaux * Il existe trois `FILE *`{.C} qui existent pour tout programme: * `stdin`{.C}: l'entrée standard. * `stdout`{.C}: la sortie standard. * `stderr`{.C}: l'erreur standard. * Lors d'un fonctionnement dans le terminal: * l'entrée standard est le *clavier* * la sortie et erreur standard sont affichés dans le *terminal*. * Ainsi on a ```C fprintf(stdout, "texte\n"); // == printf("texte\n"); int a; fscanf(stdin, "%d", &a); // == scanf("%d", &a); ```