Le langage C
Base de donnée: Entrées/sorties en C (suite)

Par :
Guilhem de Wailly (gdw@erian-concept.com)

Résumé
Dans cette série d'articles, nous présentons le langage C. Il ne s'agit pas de réécrire les ouvrages de référence donnés en annexe, mais de donner, au travers du C, une méthode de programmation basée sur la notion d'interface.
Au fur et à mesure de notre progression, nous décrirons les éléments indispensables du langage et conduirons le lecteur à consulter les ouvrages de références. Le but poursuivi est clairement de parvenir à construire des programmes de manière segmentée.
Ce mois-ci, nous allons nous continuer à nous intéresser aux tables de hachage réalisées en C. Nous avons déjà pu aborder ce sujet avec le langage Scheme dans le numéro 6 de Linux Magazine. Cette réalisation permettra de réaliser de petites bases de données.
Nous allons plus particulièrement nous pencher sur les fonctions d'entrées/sortie proposées par le langage C.
Description
Les entrées/sorties permettent d'effectuer des échanges d'informations entre la mémoire centrale de l'ordinateur et les mémoires secondaires que sont les disquettes, les disques dur, les lecteur réseau, etc. L'avantage de la mémoire centrale est sa vitesse et ses inconvénients sont que son contenu est effacé lorsque l'ordinateur est éteint et que son prix est élevé. Les avantages de la mémoire secondaire sont que son contenu reste écrit même lorsque le périphérique est éteint et que son coût est plus faible que celui de la mémoire principale, mais son inconvénient est sa faible vitesse.
Compte tenue des avantages et inconvénients de ces systèmes de stockage, les ordinateurs ont depuis l'origine été dotés de périphériques de stockage. Par le passé, les informations étaient rangées sur des fiches en carton perforé, et un programme était écrit sur plusieurs centaines de fiches. On a eu aussi les cassette audio avec les premiers ordinateurs familliaux, et les nostalgiques se rappellerons avec émotion le doux bruit du transfert de fichiers. Mais le roi du périphérique de stockage secondaire est sans conteste le disque dur qui n'a cessé d'évoluer dans le sens d'une augmentation de la capacité de stockage et de la vitesse d'accès et une diminution du prix.
Dans l'avenir, l'octet en mémoire vive coûtera toujours plus cher que l'octet sur le disque dur. Il y fort à parier que les ordinateurs de bureau de demain seront toujours dotés de disques durs. Mais on commence à voir apparaître des ordinateur sans stockage secondaire où tout est en mémoire vive de type flash, qui gardent leur contenu même lorsqu'elle n'est plus alimentée en courant.
Pour ces raisons, on trouve dans quasiment tous les programmes fabriquant et manipulant de l'information un dispositif permettant d'échanger ces informations avec la zone de stockage secondaire. A part pour certaine programmes évolués, ces échanges se résument en deux fonctions C, l'une pour écrire les informations, et l'autre pour les lire.
Nous allons dans un premier temps examiner les principales fonctions que la bibliothèque standard du langage C met à notre disposition pour exploiter les zones de stockage secondaires.
Les entrées/sorties peuvent être réalisées en C de deux manières : soit de manière élémentaire en accédant directement au système d'exploitation, soit au travers d'un tampon en mémoire vive. Attention, les entrées tamponnées ne signifient pas que l'on accède au cache du disque, mais que l'application elle-même gère un cache. 
Entrée/sorties élémentaires
Les entrées/sorties élémentaires offrent peu de fonctions. Elles sont interfacées directement avec le système d'exploitation. On les utilisent lorsque le fichier ouvert est en réalité relié par le noyau à un périphérique, ou que l'on souhaite réalisé soit-même un mécanisme de cache.
Création, Ouverture et fermeture
Un fichier ouvert est représenté dans l'application par un nombre entier appelé descripteur de fichier et que l'on obtient en appelant les fonctions suivantes :
int open (char * nom, int mode)
int creat (char * nom, int mode)
Les prototypes de ces fonctions sont situés dans l'entête fcntl.h.
Si le fichier est correctement ouvert, la fonction open retourne un nombre entier positif ou nul. En cas d'erreur, elle retourne -1. Le nom du fichier est une chaîne de caractères pouvant contenir un chemin. L'argument mode permet de définir le mode d'ouverture du fichier. C'est une combinaison des constantes suivantes reliées par l'opérateur ou binaire : 
·	O_RDONLY pour l'ouverture en lecture seule, 
·	O_WRONLY pour l'ouverture en écriture seule, 
·	O_RDWR pour l'ouverture en lecture écriture,
·	O_CREAT pour créer le fichier s'il n'existe pas,
·	O_APPEND pour ajouter les informations à la fin du fichier.
·	O_TRUNC pour tronquer le fichier, s'il existe.
Il existe d'autres constantes gérant la manière de partager le fichier ouvert, ou le type de synchronisation souhaité. Tout cela est bien expliqué dans le manuel de la fonction open. 
On pourra par exemple avoir :
int fichier = open ("/etc/passwd", O_RDONLY);
Pour créer un fichier, ou pourra préférer la fonction creat.
Le nombre de fichiers simultanément ouverts pour une application est limité (la valeur est  OPEN_MAX). Il est donc important de fermer un fichier dès qu'il devient inutile :
int close (int descripteur)
Cette fonction ferme le fichier dont le descripteur est donné en argument. En cas de succès, elle retourne 0, et -1 en cas d'échec.
Maintenant que nous savons créer, ouvrir et fermer les fichiers, nous souhaitons accéder à leur contenu.
Lecture et écriture
int read (int descripteur, void * tampon, int taille)
Cette fonction permet de lire taille octets à partir du fichier descripteur et de les placer dans tampon. Attention, tampon est un pointeur vers une zone de mémoire allouée (soit déclarée comme un tableau de caractères, soit allouée avec la fonction malloc). 
Pour pouvoir lire dans un fichier, celui-ci doit être ouvert dans un mode autorisant la lecture ; il faut aussi que l'utilisateur UNIX effectuant la lecture ait les droits suffisants, au niveau du système d'exploitation, pour lire le fichier.
La fonction retourne un entier qui est le nombre d'octets effectivement écrits dans le tampon ou -1 en cas d'erreur. Le nombre d'octets écrits peut être inférieur au nombre d'octets demandés si le fichier est trop petit.
La lecture dans un fichier provoque le déplacement du curseur de fichier de sorte que la prochaine lecture/écriture dans le fichier se fera à partie de la nouvelle position du curseur.
Par exemple :
int  descripteur = open ("/etc/passwd", O_RDONLY);
char tampon[512];

read (descripteur, tampon, sizeof (tampon));
close (descripteur);
int write (int descripteur, void * tampon, int taille)
La fonction d'écriture reprend les mêmes paramètres, mais cette fois-ci, tampon contient les octets à écrire à la position courante du fichier. La fonction retourne le nombre d'octets effectivement écrits, ou -1 en cas d'erreur. Le nombre d'octets écrits est inférieur au nombre d'octets en cas d'erreur.
Pour pouvoir écrire dans un fichier, il est nécessaire que celui-ci soit ouvert dans un mode autorisant l'écriture. La lecture dans un fichier provoque le déplacement du curseur de fichier.
Par exemple :
int descripteur = open ("/tmp/test", O_RDWR);
char      * str = "un chaîne de caractères";

write (descripteur, str, strlen (str));
close (descripteur);
Dans cet exemple, on remarque que la taille n'est pas spécifiée par sizeof (str), car cette valeur est la taille d'un pointeur vers un caractère, qui vaut quatre octets ; au contraire, il est nécessaire de calculer la longueur de la chaîne de caractères avec la fonction strlen.
Interrogation
int lseek (int descripteur, int position, int mode)
Cette fonction déplace le pointeur du fichier descripteur à la position indiquée, relativement à l'origine spécifiée par mode. En cas de succès, cette fonction retourne l'ancienne position du curseur de fichier, et -1 en cas d'échec.
L'argument mode peut prendre l'une des valeurs constantes suivantes :
·	SEEK_SET : la position est donnée par rapport au début du fichier ;
·	SEEK_CUR : la position est donnée par rapport à la position courante du curseur ;
·	SEEK_END : la position est donnée par rapport à la fin du fichier.
Par exemple, la fonction suivante permet de calculer la longueur du fichier dont le nom est donnée en argument :
/* retourne la taille du fichier ou -1. */
int longueur (char * fichier) {
  int retour, descripteur;

  /* ouverture du fichier et test. */
  descripteur = open (fichier, O_RDONL);
  if (descripteur < 0) return (-1);
  
  /* positionnement à la fin du fichier. */
  lseek (descripteur, 0, SEEK_END);
  
  /* positionnement au début du fichier.
  * la valeur de retour est la position
   * courante, c'est  à  dire  la taille
   * recherchée. */
  retour = lseek (descripteur, 0, SEEK_SET);
  
  /* fermeture du fichier et retour. */
  close (descripteur);
  return (retour);
}
Pour obtenir un maximum d'informations sur un fichier ouvert, il existe la fonction suivante.
int fstat (int descripteur, struct stat * buf)
Cette fonction prend en argument un descripteur de fichier et un pointeur vers une structure stat déclarée dans l'entête standard sys/stat.h. Elle remplit la structure stat et retourne zéro si tout c'est bien passé et -1 en cas d'erreur.
La structure stat contient différents champs dont les principaux sont :
Par exemple:
·	umode_t st_mode : droits associés au fichier. Pour connaître le type de fichier, il existe un certain nombre de macros auxquels on donne comme argument ce champs st_mode. Ces macros retournent 1 en cas de succès et 0 sinon :
- S_ISLNK  (st_mode) : lien symbolique.
- S_ISREG  (st_mode) : un fichier régulier.
- S_ISDIR  (st_mode) : un répertoire.
- S_ISCHR  (st_mode) : un péripherique en mode caractère.
- S_ISBLK  (st_mode) : un périphérique en mode blocs.
- S_ISFIFO (st_mode) : une FIFO.
- S_ISSOCK (st_mode) : une socket.
·	nlink_t st_nlink : nombre de liens matériels sur le fichier.
·	uid_t st_uid : numéro du propriétaire (UID).
·	gid_t st_gid : numéro de groupe du propriétaire (GID).
·	off_t st_size : taille totale en octets.
·	time_t st_atime : date du dernier accès. Les dates retournées sont le nombre de secondes écoulé depuis le 1er janvier 1970. Elles peuvent être converties en chaînes de caractères lisibles avec la fonction ctime, comme nous le verrons dans l'exemple.
·	time_t st_mtime : date de la dernière modification.
·	time_t st_ctime : date du dernier changement.
Le programme suivant affiche les informations relative au fichier dont le nom est passé en argument : 
#include <sys/stat.h>

/* Affiche des informations sur le fichier.
 * Retourne 0 en cas de succès ou -1 en cas
 * d'erreur. */
int informations (char * fichier) {
  int         descripteur, erreur;
  struct stat infos;
  char      * date;

  /* ouverture du fichier et test. */
  descripteur = open (fichier, O_RDONL);
  if (descripteur < 0) return (-1);
  
  /* Obtention des informations. */
  erreur = fstat (descripteur, & infos) == -1;

  /* fermeture du fichier et retour. */
  close (descripteur);

 if (erreur) return (-1);

  /* affichage des informations. */
  printf ("fichier = %s est un", fichier);
 if      (S_ISLNK (infos.st_mode))printf(" lien symbolique\n");.
 else if (S_ISREG (infos.st_mode))printf(" fichier régulier.");
  else if (S_ISDIR (infos.st_mode))printf(" répertoire.");
 else if (S_ISCHR (infos.st_mode))printf(" péripherique caractère.");
  else if (S_ISBLK (infos.st_mode))printf(" périphérique blocs.");
  else if (S_ISFIFO(infos.st_mode))printf("e FIFO.");
  else if (S_ISSOCK(infos.st_mode))printf("e Socket\n");
  printf ("liens = %d\n", infos.st_nlinks);
 printf ("UID   = %d\n", infos.st_uid);
 printf ("GID   = %d\n", infos.st_gid);
 printf ("Taille= %d\n", infos.st_size);
 printf ("Accès = %s\n", ctime (& infos.st_atime));
 printf ("Modif = %s\n", ctime (& infos.st_mtime));
 printf ("Changé= %s\n", ctime (& infos.st_ctime));
 
  return (0);
}
Il existe d'autres champs dans la structure stat. Il existe aussi la fonction lstat qui revoie plus d'informations encore. Le lecteur pourra consulter les pages de manuels.
Autres fonctions
Il existe d'autres fonctions, comme dup et dup2 qui permettent du dupliquer un descripteur de fichier, ioctl qui permet de paraméter certains périphériques comme le terminal.
Il existe aussi un jeu de fonctions dont mmap est la principale qui permettent de transformer un fichier en une zone de mémoire (mapper le fichier en mémoire). La lecture se fait alors au moyen d'un pointeur, ce qui est très commode et efficace.
Pour toutes ces fonctions, il existes des pages de manuels.
Les fonctions d'entrées/sorties que nous venons d'examiner invoquent directement le système d'exploitation. Lorsque l'on lit un fichier caractère par caractères, comme dans le cas d'un analyseur de compilateur, on est obligé d'appeler la fonction read pour chaque caractère. Ceci n'est pas très efficace car les appels systèmes sont des fonctions particulières qui ont un protocole d'appel plus complexe que de simples fonctions utilisateur. Dans le cas de la lecture caractère par caractère, il serait plus judicieux de lire d'un coup un grand bloc d'octets du fichier et de les placer dans un tampon ; on pourra alors lire ce tampon avec un pointeur, en prenant garde de ne pas aller au-delà du tampon.
On appelle ce tampon un cache. Cette possibilité d'effectuer les entrées/sorties au travers d'un cache existe dans la norme ANSI du langage C, et c'est ce que nous allons maintenant examiner.
Entrée/sorties avec tampon en mémoire
Dans la suite, un appellera ``flux'' un fichier avec tampon. Pour utiliser les fonctions de flux, il est nécessaire d'inclure l'entête standard stdio.h.
Ouverture et fermeture
FILE * fopen (char * nom, char * mode)
Cette fonction ouvre le fichier nom dans le mode mode, et retourne le flux. En cas d'erreur, le pointeur nul est retourné. Le mode d'ouverture est l'une des chaînes de caractères suivantes :
·	"r" : Ouvre  le  fichier  en lecture. Le curseur du flux est placé au début du fichier.
·	"r+" : Ouvre le fichier en lecture et écriture.  Le  curseur du flux est placé au début du fichier.
·	"w" : Ouvre  le  fichier en écriture. Le fichier est créé s'il  n'existait  pas.   S'il  existait  déjà,   il est tronqué.  Le pointeur de flux est placé au début du fichier.
·	"w+" : Ouvre le fichier en lecture et écriture. Le fichier est  créé s'il n'existait pas.  S'il existait déjà, il est tronqué.  Le pointeur  de  flux est placé au début du fichier.
·	"a" : Ouvre  le  fichier en écriture. Le fichier est créé s'il n'existait pas. Le pointeur de flux est  placé à la fin du fichier.
·	"a+" : Ouvre  le  fichier  en  lecture  et  écriture.   Le fichier est créé s'il n'existait pas.  Le  pointeur de flux est placé à la fin du fichier.
La fonction retourne un pointeur vers une structure de type FILE. La description de cette structure est publique, mais elle dépend du système d'exploitation. C'est typiquement le cas où la structure de donnée est connue et publique, mais où il ne faut absolument pas utiliser cette information. Dans notre présentation du langage C, les structures de données ne sont jamais publiques ; seuls les type ``pointeur sur les structures'' sont déclarés. De cette manière, l'organisation interne de la structure reste sous notre contrôle et nous pouvons l'améliorer à notre guise.
FILE * freopen (FILE * flux, char * mode)
Cette fonction permet de réouvrir un flux déjà ouvert. Elle retourne un nouveau flux. En cas d'erreur, le pointeur nul est retourné.
Elle permet essentiellement de modifier le mode d'ouverture du flux original.
int fclose (FILE * flux)
Cette fonction ferme le flux passé en argument. Elle retourne zéro en cas de succès, et EOF en cas d'erreur. EOF est une constante définie dans stdio.h qui indique la fin de fichier, ou les erreurs.
Passage entre entrées/sorties élémentaires et avec tampon
Les fonctions d'entrée/sorties avec flux sont basées sur les fonction d'entrées/sorties élémentaires, vues au début de l'article. Il existe des fonctions pour passer d'un flux à un descripteur de fichier et vice et versa :
int fileno (FILE * flux)
La fonction fileno retourne le descripteur de fichier associé au flux donnée en argument. En cas d'erreur, elle retourne -1. Les descripteurs retournés peuvent alors être manipulés par les fonctions d'entrées/sorties standards, mais attention à la cohérence !
FILE * fdopen (int descripteur, char * mode)
La fonction fdopen retourne un flux dont le descripteur de fichier est donné en argument ; le flux est ouvert avec les attributs indiqués par mode, dont la valeur est la même que pour la fonction fopen. En cas d'échec, la fonction retourne le pointeur nul.
Fichiers standards
Tout programme UNIX est créé avec des flux standards pré-définis, l'un pour les entrées, l'autre pour les sorties et le troisième pour les erreurs. Ces flux sont placés respectivement dans les variables globales stdin, stdout et stderr de type pointeur sur la structure FILE. La plupart des commandes UNIX fonctionnent soit avec un ou plusieurs nom de fichiers passés sur la ligne de commande, soit avec un flux standard.
Par exemple, la commande wc qui compte le nombre de caractères, de mots et de lignes opère soit sur son entrée standard, soit sur des fichiers dont les noms sont placés en arguments.
Par défaut, l'entrée standard est reliée au clavier, la sortie standard et la sortie des erreurs standard sont reliées à l'écran.
Lecture et écriture
Les deux fonctions suivantes sont très similaires à read et write vues précédemment, à différence qu'elles opèrent sur des flux et quelles ne manipulent pas des octets, mais des éléments.
int fread (void * tampon, int taille, in nombre, FILE * flux)
La fonction fread lit dans le flux nombre éléments de taille octets et les place dans le tampon. Elle retourne le nombre d'éléments effectivement lus. Le curseur du flux est déplacé du nombre d'oecte lus.
int fwrite (void *, int taille, int nombre, FILE * flux)
La fonction fwrite écrit dans le flux nombre éléments de taille octets à partir du tampon. Elle retourne le nombre d'éléments effectivement lus. Le curseur du flux est déplacé du nombre d'octets écrits.
Interrogation
long ftell (FILE * flux)
Cette fonction retourne la position courante du curseur de flux. En cas d'erreur, elle retourne -1.
int fseek (FILE * flux, long position, int origine)
Cette fonction déplace le curseur de flux de position octets par rapport à l'origine. Elle retourne la position précédente, en cas de succès, et -1 en cas d'erreur.
int feof (FILE * flux)
Cette fonction retourne zéro si le curseur du flux n'a pas atteint la fin du fichier, et une valeur non nulle dans le cas contraire. En cas d'erreur, elle retourne -1.
Entrées/sorties avancées
Les fonctions que nous venons de voir pour les flux sont très similaires que celles s'appliquant à des descripteurs de fichiers, à ceci près quelles gèrent un tampon en mémoire vive.
Les fonctions suivantes permettent d'effectuer des entrées/sorties plus élaborées, et elles constituent un grand avantage sur les fonctions basiques.
int fputc (int caractère, FILE * flux)
int putc (int caractère, FILE * flux)
int putchar (int caractère)
Ces fonctions permettent d'écrire un caractère dans un flux ; sauf la dernière qui écrit le caractère dans le flux de sortie standard (stdout). Les deux dernières fonctions sont réalisées sous la forme de macros ; cela les rend plus performantes, mais lorsque l'on doit absolument utiliser une fonction, on choisira la fonction fputc.
On notera que le caractère est représenté sous la forme d'un entier, sa valeur ASCII, la conversion étant faite automatiquement par le compilateur.
Ces fonctions retournent toutes le caractère écrit, ou EOF en cas d'erreur.
int fgetc (FILE * flux)
int getc (FILE * flux)
int getchar()
Ces fonctions retournent un caractère lut depuis le flux, sauf la dernière qui lit le caractère depuis l'entrée standard (stdin). Les deux dernières sont des macros. Elles retournent le caractère lu sous la forme d'un entier représentant da valeur ASCII, ou EOF en cas d'erreur.
int ungetc (int caractère, FILE * flux)
Cette macro annule la lecture de caractère précédente en replaçant le caractère dans le flux. Elle ne peut pas être appelée successivement sans qu'une lecture ne sépare les deux invocations. Cette macro est très utilisée lorsque l'on réalise des analyseurs lexicaux pour les compilateurs. 
La valeur retournée est le caractère passé en argument, ou EOF en cas d'erreur.
char * fgets (char * tampon, int taille, FILE * flux)
char * gets (char * tampon)
Ces fonctions lisent une chaîne de caractères depuis le flux pour la première ou depuis le flux d'entrée standard (sdtin) pour la seconde. La chaîne lue est placée dans le tampon. En entrée, une chaîne se termine soit lorsque la fin du fichier est rencontrée soit lorsque un saut de ligne est rencontré (dans ce cas, le saut de ligne est inclus dans le tampon).
ATTENTION : la fonction fgets contrôle que le nombre de caractères écrits dans le tampon ne dépasse pas la taille donnée en argument. La fonction gets, quant à elle, n'effectue aucun contrôle: si le tampon est capable d'accueillir 10 caractères et que la fonction en écrit 10000, il y aura certainement une erreur ! C'est l'une des fonctions responsable des trous de sécurité connus sous le nom de buffer overflow. Son usage est à déconseillé, sauf si on sait ce que l'on fait.
Exemple : nous allons écrire un programme qui remplace tous les caractères minuscule lus depuis l'entrée standard par des majuscules sur la sortie standard :
#include <stdio.h>

void main (void) {
 /* itération */
 while (1) {
  /* lecture du caractère */
  int caractere = getc (stdin);
  
  /* si fin de fichier, fin de l'itération */
  if (caractere == EOF) break;
 
  /* si minuscule, alors conversion */
  if ('a' <= caractere && caractere <= 'z')
   caractere = caractere - 'a' + 'A';
 
  /* écriture sur la sortie standard */
  putc (caractere, stdout);
 }
 /* c'est tout :) */
}
On compile ce programme et on l'exécute :
$ gcc -o maj maj.c
$ maj < /etc/passwd
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
BIN:X:1:1:BIN:/BIN:
DAEMON:X:2:2:DAEMON:/SBIN:
ADM:X:3:4:ADM:/VAR/ADM:
LP:X:4:7:LP:/VAR/SPOOL/LPD:
SYNC:X:5:0:SYNC:/SBIN:/BIN/SYNC
SHUTDOWN:X:6:0:SHUTDOWN:/SBIN:/SBIN/SHUTDOWN
HALT:X:7:0:HALT:/SBIN:/SBIN/HALT
GDW:X:500:500:GUILHEM DE WAILLY:/HOME/GDW:/BIN/BASH
OSM:X:501:501:OPENS-CHEME:/HOME/OSM:/BIN/BASH
int fprintf (FILE * flux, char * format, ...)
int printf (char * format, ...)
Eh oui, voilà enfin printf, fonction expliquée dans le deuxième article de la série C !
Ces fonctions effectuent des écritures formatées respectivement dans le flux donnée en argument ou dans le flux de sortie standard. La chaîne de format contrôle la manière de traiter les arguments supplémentaires donnés lors de l'appel à la fonction. Le lecteur fidèle pourra se référer au deuxième article sur le langage C de Linux Magazine et au pages de manuels. La fonction retourne le nombre d'octets effectivement écrits, ou EOF en cas d'erreur.
Cette chaîne de format est affichée telle quelle, mis à part un certain nombre de séquences de caractères qui modifient l'affichage :
·	\n est remplacé par un saut de ligne ;
·	\t est remplacé par une tabulation ;
·	\b est remplacé par un retour arrière ; si le curseur est en début de ligne, \b n'a aucun effet ; sinon, le caractère avant le curseur est effacé si le curseur est déplacé de un caractère vers la gauche ;
·	\" est replacé par un guillemet ;
·	%c est remplacé par l'argument supplémentaire correspondant lu comme un caractère ; attention contrôle de type n'est effectué sur les arguments supplémentaires ;
·	%d : argument entier ;
·	%f : argument réel ;
·	%p : argument pointeur (nous en parlerons plus tard) ;
·	%s : argument chaîne de caractère ;
int fscanf (FILE * flux, char * format, ...)
int scanf (char * format, ...)
Ces fonctions effectuent une lecture respectivement depuis le flux donné en argument, ou depuis le flux d'entrée standard. La chaîne de format répond aux mêmes prérogatives que pour la fonction printf. Les valeurs lues sont placées aux adresses passées en arguments supplémentaires.
Ces fonctions retournent le nombre d'arguments supplémentaires lus correctement depuis le flux.
Contrôle du tampon
int fflush (FILE * flux)
Cette fonction permet de vider le contenu du tampon sur le périphérique de sortie (synchronisation). La fonction retourne zéro en cas de succès, et EOF en cas d'échec.
int setbuf (FILE * flux, char * tampon)
Cette fonction permet de modifier le tampon associé au flux. Si tampon est le pointeur nul, l'utilisation du cache est invalidée et les entrées/sorties sont effectuées directement vers le périphérique. Sinon, tampon doit pointer vers une zone mémoire de BUFSIZ octets. La fonction retourne zéro en cas de succès, et EOF en cas d'échec.
On utilisera cette fonction principalement pour annuler l'utilisation du cache.
Manipulation externe
Les fonctions suivantes n'ont rien à voir avec les entrées/sorties formatées, mais elles sont bien pratiques lorsque l'on manipule des fichiers. Leur prototype est donné dans le fichier unistd.h.
int unlink (char * nom)
Cette fonction permet de supprimer le fichier nom. Elle retourne 0 si tout c'est bien passé et -1 en cas d'erreur.
int rename (char * ancier_nom, char * nouveau_nom)
La fonction rename permet de renommer le fichier ancien_nom en nouveau_nom. Elle retourne 0 en cas de succès et -1 dans le cas contraire.
int stat (char * nom, struct stat * tampon)
Cette fonction opère comme la fonction fstat vue au début, mais elle agit sur un fichier non ouvert, spécifié par son nom.
Voilà notre tour d'horizon des entrées/sorties en C terminé. La prochaine fois, nous utiliserons tout cela pour réaliser la sauvegarde et la restauration des tables de hachages sur disque.
L'auteur
Guilhem de Wailly, directeur de la société Erian Concept, partenaire NetUltra (www.netultra.net)  et Getek (www.getek.fr).
	Votre interlocuteur Linux !
Support, formations, configurations, administration, développements Linux.
 http://www.erian-concept.com	
Références
Langage C - norme ANSI : bon ouvrage de référence
Ph. DRIX
Masson
Programmer en C++: une bonne référence
S.C. DEWHURST et K.T. STARK
Masson
Le Langage C: la bible!
B.W. KERNIGHAN et D.M. RITCHIE 
Masson
gcc: compilateur C du GNU, et tous les outils de développement
http://www.gnu.org
Kdevel: un environnement KDE de programmation C
http://samuel.cs.uni-potsdam.de/~smeier/kdevelop_new/index.html