# Fonctions de base en langage C/stdio.h
## Description

Le fichier en-tête stdio.h contient les déclarations d'un ensemble de fonctions qui gèrent les entrées/sorties des programmes écrits en C. On y trouve aussi des constantes utiles pour rendre les programmes portables : FILENAME_MAX, BUFSIZ, EOF..., des fonctions pour renommer, détruire des fichiers et créer des fichiers temporaires.
Les fonctions d'entrée/sortie sont basées sur des mécanismes complexes.

## Les fonctions d'entrées sorties

Les fonctions d'entrées sorties reposent sur une structure FILE remplie par la fonction fopen. Dans la suite, FP désignera un pointeur sur une structure FILE (file handle en anglais) associée à une source ou une destination de données liée à un fichier sur disque dur ou sur un autre périphérique. On parle aussi de flux (stream en anglais) de données associé à un fichier externe.

### Bufferisation

Les fonctions d'entrée/sortie contrairement aux fonctions systèmes comme open, read et write, sont dîtes bufferisée : Les données peuvent être transmises par blocs.
Elles apportent aux programmeurs une gestion automatique de mémoires tampons qui évitent de faire à chaque demande d'entrées/sorties des accès aux périphériques très coûteux en temps.
Les fonctions de la famille de setvbuf permettent de contrôler précisément ce fonctionnement pour optimiser un programme. les fonctions fflush et fpurge permettent de vider ou d’effacer les mémoires tampons à tout moment.

### Flux associés par défaut à un programme

Des constantes de type pointeur sur FILE sont ouverts automatiquement :
* stdin (entrée standard) pointe sur le buffer du clavier
* stdout (sortie standard) pointe sur le buffer de l'écran
* stderr (sortie des erreurs) pointe sur la sortie des erreurs associée elle aussi à l'écran. Ce flux provoque une écriture immédiate.
Des fonctions spécifiques sont fournies pour les manipuler :
* on obtient leur nom en supprimant le f de départ des noms des fonctions d'entrée sortie sur fichier.
* on ne leur passe pas de paramètre FP (pointeur sur structure FILE *).
* exemple : printf(...) pour fprintf(stdout, ...), scanf(...) pour fscanf(stdin,...), ...
* Attention : certaines fonctions spécifiques ne se comportent pas comme leurs homologues :
** putchar(c) pour fputc(c, stdout);
** puts(str) ajoute un saut de ligne, contrairement à fputs(str, stdout);
** gets(str) beaucoup moins sûre que fgets(str, size, stdin) (risque de débordement de str).

### Exemple simple d'écriture de texte dans un fichier

Le programme suivant ecritFichier.c écrit une chaine de caractères dans un fichier. Voir ses commentaires pour plus d'explications.

### Codes Retours

Pour obtenir un programme robuste, il faut impérativement tester les codes retours des fonctions d'entrée/sortie et agir en conséquence : informer l'utilisateur, entreprendre un autre traitement, arrêter le programme.
* Les tests if (hFile == NULL) et if (codeRetour == EOF) sont nécessaires, mais pas suffisants : l'appel à la fonction perror permet d'afficher la cause de l'erreur codée dans la variable globale errno sur stderr. Il faut appeler au plus tôt perror après l'erreur, car tout appel système ultérieur modifiera errno en cas de problème.
* Par exemple, si le fichier bonjour.txt n’est pas accessible en écriture, on obtient :
* Les causes d'erreur peuvent être nombreuses : fichier non accessible, espace disque insuffisant... :Pour les connaître, consultez le chapitre ERRORS des pages de man des fonctions de niveau 3, exemple : man fputs.
    On voit ici, qu’il faut aussi regarder la page de man de la fonction de niveau 2 (système) write : man -s2 write.
* Les constantes symboliques correspondant aux codes d'erreur sont dans errno.h
* Utilisation de la fonction c99 strerror :
    Il faut sauver ou exploiter errno au plus vite après l'erreur.

### Erreurs fréquentes et recommandations

* Lors de l’utilisation de printf, une erreur d'exécution fréquente est due à la non concordance en nombre ou type entre les variables à traiter et les spécificateurs de format.
* Une erreur grave consiste à passer aux fonctions de la famille scanf une valeur au lieu d'une adresse.
* Il est préférable d’utiliser les fonctions de lecture comme fgets, snprintf qui permettent de spécifier la taille maximale de de la chaine recevant la lecture pour éviter les débordements.
* Les fonctions fwrite et fread permettent respectivement d'écrire et de lire des données binaires dans un flux. Ce flux doit être ouvert à l'aide de la fonction fopen en spécifiant le caractère b (rb, rb+, wb) pour l'attribut mode : sa présence indique (pour certains systèmes comme MS-DOS) qu’il s'agit d'un flux binaire et non d'un flux caractère. Les données lues ne devront pas être modifiées (caractère ASCII 0xA (\n) transformé en 0xAD (\n\r)). Pour la portabilité de vos programmes qui écrivent ou lisent des données binaires, ne pas l'oublier!
** La relecture de données binaire sur une même machine ne pose pas de problèmes. Sur des machines différentes, l'exercice pourra être plus difficile : problème d'ordre des octets : little/big endian, taille des types différents.
** La solution pourrait être :
*** d’utiliser les fonctions ASCII du chapitre précédent si les volumes sont faibles.
*** d'appeler les fonctions d'une bibliothèque spécialisée
*** de greffer à votre code un compresseur de données genre gzip si les données sont volumineuses.
* Les fonctions de positionnement dans un fichier permettent de travailler sur disque avec un volume de données en mémoire minimum, mais les temps d'exécution peuvent augmenter.

## Création de fichiers temporaires
### Rôle

Les fichiers temporaires servent aux programmes à stocker sur disque des informations qu’il pourra réutiliser plus tard lors de son exécution. Cette manœuvre peut permettre :
* de traiter les informations un peu plus tard par une fonction séparée.
* d'économiser de la place en mémoire vive en stockant sur disque, par exemple, des informations relatives à une tâche qui devient moins prioritaire.

### tmpfile

La fonction tmpfile de stdio.h permet de créer en lecture écriture un fichier qui sera automatiquement effacé lorsqu’il sera fermé. Il sera créé dans un répertoire spécial dont le nom se trouve dans P_tmpdir ou par exemple dans /tmp ou \temp.
Le programme suivant écrit puis relit dix entiers dans un fichier temporaire :

### tmpnam

Cette fonction de prototype char *tmpnam(char *str) retourne un nom de fichier temporaire mais ne l'ouvre pas comme tmpfile. C'est à vous d'ouvrir le ficher et de le détruire. Le nom créé débute par le contenu de la variable P_tmpdir de stdio.h. Vous lui passez en paramètre :
* NULL : alors le nom sera généré dans une zone statique de tmpnam et pourrait être écraser lors d'un prochain appel.
* Soit une chaîne de caractère que vous aurez définie de longueur au moins L_tmpnam.
Limite : tmpnam retourne une chaîne de caractères différente pour TMP_MAX appels successifs. TMP_MAX, défini dans stdio.h vaut au minimum 25, pour un système Mac OS X.4 : 308915776.
Exemple d’utilisation :

### Autres fonctions

Les systèmes genre UNIX offrent d'autres fonctions pour respectivement la création : de noms de fichiers, de fichiers et de répertoires temporaires : mktemp, mkstemp, mkdtemp.

### Problèmes de sécurité possibles

Si les données à stocker dans le fichier temporaire ne doivent pas être connues hors du programme, certaines fonctions peuvent poser des problèmes de sécurité :
* Les fichiers peuvent être créés avec des droits d'accès trop ouverts.
* Des programmes malveillants peuvent scruter certains répertoires pour connaître les fichiers créés et piller les données contenues.
* Certains artifices malveillants peuvent agir dans la phase située entre la création du nom de fichier et son ouverture.

## Gestion de fichiers
### Généralités

stdio.h fournit les prototypes de deux fonctions remove et rename qui permettent de détruire ou de renommer un fichier.
D'autres fonctions de manipulation du système de fichier sont standardisée par la norme POSIX 1003.1.

### remove : suppression de fichier

La fonction remove supprime un fichier ou un répertoire vide de la liste des entrées d'un répertoire. Elle retourne 0 en cas de succès.

### rename : renommer un fichier ou un répertoire

La fonction rename permet de changer le nom d'un fichier ou d'un répertoire. Elle accepte deux chaînes de caractères en paramètre :
* la première est le nom du fichier à renommer,
* le deuxième est son nouveau nom.
Elle retourne 0 en cas de succès ou un code d'erreur en cas de problème.
| math.h | stdlib.h |