Next: 9 Préprocesseur
Up: Le langage C
Previous: 7 Pointeurs
Par défaut, à tout fichier est associé un tampon de taille prédéfinie.
Cette taille est configurable
par l'utilisateur à l'aide de la fonction setvbuf.
Le passage par un tampon, s'il accélère les opérations d'entrée-sortie,
introduit un problème de
décalage dans la chronologie, puisque l'opération effective de lecture
ou d'écriture dans le fichier
n'est pas prédictible par le programmeur. Il en découle qu'une intéruption
brutale d'un programme
peut conduire à des pertes d'infomations dans les fichiers.
Les flots sont désignés par des variables de type FILE * (pointeur sur une structure de type FILE). Le type FILE est définie dans le fichier d'interface stdio.h. La défintion du type FILE est dépendant du système d'exploitation; mais il correspond à une structure (appelée descripteur) qui contient toujours les informations suivantes : l'adresse du tampon, pointeur vers le premier caractère libre du tampon, le nombre de caractères libres du tampon, l'état du fichier, etc ... Pour utiliser un fichier dans un pogrammme C, il faut donc inclure le fichier stdio.h et définir une variable par fichier.
#includeFILE *fic1, *fic2; ...
qui est utilisée pour ouvrir un fichier Cette fonction retourne un pointeur vers une structure de type FILE qui sera utilisée pour les opérations d'entrées-sorties par la suite. C'est ce pointeur qui identifie parfaitement le fichier que l'on veut utiliser. Le paramètre nom est une chaîne de carcatères qui désigne le nom du fichier. Le paramètre mode_d_accès est une également une chaîne de caractères qui spécifie le type d'opération que l'on veut effectuer sur ce fichier:
FILE *fopen(char *nom, char *mode_d_accès);
"r" | Ouvrir le fichier en lecture seule |
(Erreur si le fichier n'existe pas) | |
"w" | Ouvrir le fichier en écriture seule |
(Création du fichier si le fichier n'existe pas) | |
(Si le fichier existe, son ancien contenu sera perdu) | |
"a" | Ouvrir le fichier en ajout i.e. écriture à la fin du fichier |
(Création du fichier si le fichier n'existe pas) | |
"r+" | Ouvrir le fichier en lecture et écriture |
(Erreur si le fichier n'existe pas) | |
"w+" | Ouvrir le fichier en lecture et écriture |
(Création du fichier si le fichier n'existe pas) | |
(Si le fichier existe, son ancien contenu sera perdu) | |
"a+" | Ouvrir le fichier en lecture et en ajout |
(Création du fichier si le fichier n'existe pas) | |
Lorsqu'il y a une erreur, le programme ne s'arrête pas; la fonction renvoie
la valeur
NULL (qui vaut 0). C'est au programmeur de tester cette valeur
chaque fois
qu'il appelle cette fonction.
A priori, pour utiliser des fichiers binaires, il faut ajouter le caractère b dans ces chaînes ("ab+", "wb+","rb", etc...) mais certains systèmes s'en passent.
main() { FILE * flot; flot = fopen("xxx.c", "r"); if (flot == NULL) { printf("Erreur d'ouverture du fichier %s", "xxx.c"); exit(0); } }
qui est utilisée pour fermer un fichier. Le paramètre flot est une pointeur vers une structure de type FILE, qui est presque toujours la valeur retounée par un appel à la fonction fopen. La fonction fclose retourne EOF (End Of File) si la fermeture du fihcier s'est mal passée. Sinon, c'est la valeur 0 qui est retournée.
int fclose(FILE *flot);
Cette fonction provoque l'écriture physique immédiate du tampon à la demande et non lorsque le système le décide (voir 8.1). Elle rend EOF en cas d'erreur et 0 dans les autres cas.
int fflush( FILE *flot);
Cette fonction retoune le pointeur vers le flot ou NULL en cas d'erreur.
FILE *tmpfile (void);
Cette fonction redéfinit la politique de gestion du tampon d'entrée-sortie.
Il y a trois choix dans la politique de gestion des tampons :
int setvbuf( FILE *flot, char *buf, int mode , size_t taille);
Normallement, tous les fichiers sont associés à des tampons bloc. La fonction setvbuf peut être utilisée pour changer le type de tampon utilisé. Le paramètre mode doit être l'une des trois constantes symboliques:
A l'exception des fichiers sans tampon, le paramètre buf doit être un pointeur vers un tampon de taille plus grande ou égal à taille. C'est la mémoire fournie par la varibale buf qui sera alors utilisé comme tampon. Si le pramètre buf est la constante NULL, la fonction alloue son propre espace pour le tampon. La fonction setvbuf ne doit pas être utilisée lorsque le tampon n'est pas vide: elle doit être appelée avant toute opération d'entrée-sortie (et après un fopen) ou immédiatement après un appel à fflush.
La fonction feof teste l'indicateur de fin de fichier du flot spécifié par le parmètre flot et retourne une valeur non nulle.
Cette fonction doit être appelée immédiatement après une opération d'entrée-sortie pour savoir si cette opération a échoué ou pas. La variable globale errno définie dans le fichier errno.h contient un code permettant connaître plus précisement la nature de l'erreur.
int feof(FILE * flot);
Par défaut, lorsqu'un programme débute, il existe trois flots prédéfinis qui sont ouverts: il s'agit de stdin, stdout et stderr. Ces flots sont connectés (comme leur nom le laisse supposer) sur les organes d'entrée-sortie naturels:
Même si un programme n'utilise que ces trois flots prédéfinis, sous le système UNIX, il est possible (sans rien modifier au programme) de modifier des flots par défaut en utilisant les redirections sur la ligne de commande du lancement du programme. De même, il est possible de rediriger les sorties d'un premier programme vers l'entrée d'un deuxième programme à l'aide des tubes. Pour plus de précision, se reporter au polycopie Introduction à UNIX.
int fputc(int car, FILE *flot);
On remarquera que le type du retour de la fonction est un int (et non pas un char). Se reporter à la section 1.4.2, le paragraphe "caractère impossible" pour plus de précision.
int fgetc(FILE *flot);
font exactement la même chose que fputc et fgetc mais leur différence vient du fait qu'elles sont (pas forcément toujours) des macros donc plus efficaces. Il faut donc les utiliser avec précaution et éviter les effets de bord intenpestifs.
int putc(int car, FILE *flot); int getc(FILE *flot);
int getchar(void);
int putchar(int c);
Plus précisément, cette fonction lit taille-1 caractères dans le fichier de descripteur flot ou bien jusqu'au caratère '
char *fgets(char *s, int taille, FILE *flot);
\n
',
s'il survient avant les taille-1 caractères, (le caractère
'\n
' est copié dans le tampon). La fonction rend le pointeur vers
le début du tampon ou NULL en cas d'erreur ou de fin de flot.
Comme pour la fonction fgetc, le fonction feof permet de
vérifier s'il s'agit d'une erreur ou d'un fin de fichier.
Le dernier caractère du tampon est '\0
'
La fonction fputs écrit une chaîne de caractères
dans un flot. Cette fonction n'écrit pas le caractère '\0
'
.
La fonction retoune une valeur non négative si tout s'est bien passé. La valeur EOF indique une erreur.
int fputs(const char *s, FILE *flot);
Le flot par défaut est stdin. La fonction se comporte comme mais il n'y pas de test de débordement et le caractère de fin de ligne '
char *gets(char *s);
\n
' est remplacé par '\0
'.
La fonction puts écrit sur le flot stdout la chaîne de carcatères s.
La fonction retourne une valeur non négative si tout s'est bien passé. La valeur EOF indique une erreur. Contrairement à la fonction fputs, la fonction ajoute le caractère '
int puts(char *s);
\n
' à la
fin de l'écriture.
Les fonctions fprintf et fscanf permettent d'effecuter des lectures et écriture formatées de données dans un flot. Les
fonctions printf et scanf sont des raccourcis pour les fonctions fprintf et fscanf lorsque le flot est l'entrée standard ou la sortie standard.
int fprintf(FILE *flot, char *format, arg1, ..., argN);
Nous avons déjà rencontré ce type d'écriture dans les divers exemples des chapitres précédants. Le format général de la fonction printf est de la forme:
La fonction printf affiche les arguments donnés en fonction du format spécifié, et ce après conversion et mise en forme si nécessaire. Cette fonction retourne le nombre de caractères affichés.
int printf(const char *format, arg1, ..., argN);
Le format est une chaîne de caractères qui contient deux types d'objets: des caractères ordinaires, qui sont affichés sans aucune modification, et des spécifications, qui déterminent le type de conversion et de mise en forme à effectuer avant l'affichage proprement dit.
Toutes les spécifications commencent par le caractère % et se terminent par un un caractère de conversion. Entre ces deux caractères, on peut placer dans l'ordre:
d, i | notation décimale signée | int |
u | notation décimale non signée | int |
o | notation octale non signée | int |
x, X | notation hexadécimale non signée sans les caractères 0x ou 0X | int |
c | caractère après conversion en unsigned char | int |
s | impression d'une chaîne de caractères se terminant pas par le carcatère de fin de chaîne | char * |
f | notation décimale de la forme [-]mmm.ddd | double |
e, E | notation décimale de la forme [-]m.dddddde + ou - xx | double |
% | imprime le caractère % |
float x = 123.456; printf(">%f< ", x); >123.456001< printf(">%12f< ", x); > 123.456001< printf(">%12.2f< ", x); > 123.46< printf(">%.2f< ", x); >123.46< printf(">%-12.2f< ", x); >123.46 < printf(">%+-12.f< ", x); >+123 < printf(">% -12.2f< ", x); > 123.46 < printf(">%012.2f< ", x); >000000123.46< printf(">%.0f< ", x); >123< printf(">%#.0f< ", x); >123.<
Pour de plus de précision, consulter les pages du manuel UNIX.
Le format général de la fonction scanf est de la forme:
Cette fonction lit sur le flot, en fonction des spécifications du format, les données pour les affecter aux arguments forunis. Cette fonction rend EOF en cas d'erreur ou si la fin de flot est atteint. Sinon, elle retourne le nombre d'objets lus.
int scanf(const char *format, arg1, ..., argN);
Le format contient de spécifications comme pour le format de printf. Cette chaî ne peut contenir:
Pour de plus de précision, consulter les pages du manuel UNIX.
Jusqu'à présent, les fonctions d'entrée et de sortie que avons évoqués sont de haut niveau; il sont indépendant des systèmes d'exploitation quea l'on utilise.Nous allons nous intéresser, à présent, à des fonctions de plus bas niveau et qui peuvent différer d'un système à l'autre. Ce qui va suivre s'applique pour tous les systèmes d'exploitation UNIX.
Comme nous l'avons déjà dit, au démarrage d'un programme, trois fichiers standards sont ouverts: stdin, stdout et stderr dont les descripteurs sont respectivement 0, 1 et 2. On peut donc utiliser ces fichiers sans avoir à les ouvrir, comme c'est le cas pour tout autre flot.
Les fonctions de bas niveau open et create permettent d'ouvrir un fichier:
Ces fonction retournent un descripteur de fichier qui est un entier. Le paramètre flags a pour valeur O_RDONLY, O_WRONLY ou O_RDWR selon le l'on veuille utiliser le fichier en lecture seule, en écriture seule ou en lecture et écriture.
int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname, mode_t mode);
Le paramètre flags peut également être un entier vu comme une suite de bits que l'on postionne avec des ou (|) Les bits à positonner sont:
Le paramètre mode définit les permissions (mode & ~umask) du fichier (en cas de création). Généralement la valeur de mode est 0.
Pour plus de précisions, se reporter aux pages du manuel en ligne UNIX.
Pour utiliser ces constantes, il faut inclure le fichier
#include#include #include
La fonction create sert à créer un fichier s'il n'existe pas ou à réécrire d'anciens fichiers. Les permissons sont données en notation octale (se preporter au polycopié UNIX pour plus de précisions).
La fonction read lit, dans le fichier déisgné à partir du descripteur de fichier fd, count octets et les range dans le tableau de caractères buf.
int read(int fd, char *buf, int count); int write(int fd, const char *buf, int count);
La fonction read écrit, dans le fichier déisgné par le descripteur de fichier fd, count octets du tableau de caractères buf.
Ces fonctions renvoient le nombre d'octets effectivement transférés. On peut donc demander à lire ou écrire n octets mais si le nombre d'octets disponibles est inférieur à n , les fonctions read et write retournent le nombre d'octets effectivement transférés. La valeur 0 est retournée lorsqu'on atteint une fin de fichier et -1 pour toute autre erreur.
Pour pouvoir utiliser ces fonctions il faut inclure les fichiers .h suivants:
#include#include
Voici un petit exemple d'utilisation de ces fonctions: il s'agit d'un programme qui lit à la console une suite de caractères et qui les réécrit à la console.
int main() { char buf[10]; int n; while (n = read(0, buf, 10)) write(1, buf, n); return 0; }
Touraivane