diff --git a/Makefile b/Makefile index 85b2464b0bc2b1ebeacba57e53cb9d4c1a717f5c..b79c517815f8263a309f155d6aa5552550d892dc 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,9 @@ REVEALOPTIONS += --self-contained REVEALOPTIONS += -V revealjs-url=./reveal.js REVEALOPTIONS += -V theme=white -all: base_6.pdf base_5.pdf base_4.pdf base_3.pdf base_2.pdf base_1.pdf intro.pdf command_line.pdf index.html +all: base_7.pdf base_6.pdf base_5.pdf base_4.pdf base_3.pdf base_2.pdf base_1.pdf intro.pdf command_line.pdf index.html -all_html: intro.html base_1.html base_2.html base_3.html base_4.html base_5.html base_6.html command_line.html +all_html: intro.html base_1.html base_2.html base_3.html base_4.html base_5.html base_6.html base_7.html command_line.html intro.pdf: intro.md metadata.yaml pandoc $(PDFOPTIONS) -o $@ $^ @@ -61,6 +61,12 @@ base_6.pdf: base_6.md metadata.yaml base_6.html: base_6.md metadata.yaml pandoc $(REVEALOPTIONS) -o $@ $^ +base_7.pdf: base_7.md metadata.yaml + pandoc $(PDFOPTIONS) -o $@ $^ + +base_7.html: base_7.md metadata.yaml + pandoc $(REVEALOPTIONS) -o $@ $^ + command_line.pdf: command_line.md metadata.yaml pandoc $(PDFOPTIONS) -o $@ $^ diff --git a/base_7.md b/base_7.md new file mode 100644 index 0000000000000000000000000000000000000000..6100ac7e5876ba29e1f8665b1603c96e3e9aabba --- /dev/null +++ b/base_7.md @@ -0,0 +1,150 @@ +% Base VII +% 16 septembre 2020 + +# 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 référence*. + +# 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(RETURN_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]; +buffer = 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 à l'adresse + // buffer dans le fichier fp au format binaire + // 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); + ``` +