Sous-sections

9.2 Entrées-sorties de haut niveau

Les entrées-sorties de haut niveau intègrent deux mécanismes distincts :

Toute opération d'entrée-sortie se fera par l'intermédiaire d'un flot (stream) qui est une structure de données faisant référence à :

Cette structure de données est un objet de type FILE. Dans le programme, un flot sera déclaré de type FILE *. Trois flots sont prédéfinis au lancement d'un processus :

Les informations précédentes sont contenues dans le fichier en-tête stdio.h. Ce fichier contient, de plus, les déclarations des différentes fonctions d'entrée-sortie, ainsi que la déclaration d'un vecteur (_iob) de type FILE dont la dimension est définie à l'aide d'une pseudo-constante.

9.2.1 Fonctions d'ouverture et de fermeture

L'acquisition d'un nouveau flot s'effectue par l'appel à la fonction fopen. La fonction fclose permet de le fermer.

Syntaxe

 
FILE *fopen(const char *file, const char *type);
int   fclose(const FILE *flot);
La fonction fopen retourne un pointeur sur le 1$^{er}$ élément libre du vecteur _iob s'il en existe, sinon sur une zone de type FILE allouée dynamiquement.

Un pointeur NULL, pseudo-constante définie comme (void *)0 dans stdio.h, indique une fin anormale.

La fonction fclose retourne 0 en cas de succès, -1 sinon.

Le 2$^{e}$ argument de la fonction fopen indique le mode d'ouverture du fichier. (r,w,a)

Certains systèmes font la distinction entre les fichiers texte et binaire. Pour manipuler ces derniers, il suffit de rajouter le caractère b dans la chaîne indiquant le mode d'ouverture. Sous UNIX, il est ignoré car il n'existe aucune différence entre un fichier binaire et un fichier de données quelconques.

Exemple

 
#include <stdio.h>
main()
{
   FILE * flot;
   if ((flot = fopen("donnees", "r")) == NULL) {
     fprintf(stderr, "Erreur a l'ouverture\n");
     exit(1);
   }
   fclose(flot);
}

9.2.2 Lecture et écriture par caractère

Les fonctions getc, fgetc et putc, fputc permettent de lire ou écrire un caractère sur un flot donné.

getc et putc sont des pseudo-fonctions.

Syntaxe

 
  int getc(FILE *Stream)
  int fgetc(FILE *Stream)
  int putc(int c, FILE *Stream)
  int fputc(int c, FILE *Stream)
Il existe deux pseudo-fonctions supplémentaires :

Ces fonctions retournent soit le caractère traité, soit la pseudo-constante EOF, définie comme -1 dans le fichier stdio.h, en cas d'erreur (fin de fichier par exemple).

Deux pseudo-fonctions feof et ferror, définies dans le fichier stdio.h, permettent de tester, respectivement, la fin de fichier et une éventuelle erreur d'entrée-sortie sur le flot passé en argument.

Dans le cas d'une entrée-sortie au terminal, c'est le retour chariot qui provoque l'envoi au programme de la mémoire tampon rattachée au pilote /dev/tty.

Exemple

 
#include <stdio.h>
main()
{
  char c;  <=== Attention Erreur !
                ----------------
  while ((c = getchar()) != EOF)
     putchar(c);
}

9.2.3 Lecture et écriture de mots

Les fonctions getw et putw permettent de lire ou écrire des mots.

Syntaxe

 
  int getw(FILE *flot)
  int putw(int c, FILE *flot)

Exemple

 
#include <stdio.h>
#define DIM 100
main()
{
   FILE *flot;
   int   tab[DIM];
   int   i;
   if ((flot = fopen("resultat", "w")) == NULL) {
     perror("fopen");
     exit(1);
   }
   for (i=0; i  i < DIM; i++) {
      tab[i] = i*i;
      putw(tab[i], flot);
   }
   fclose(flot);
}

9.2.4 Lecture et écriture d'une chaîne de caractères

Les fonctions gets, fgets et puts, fputs permettent de lire et écrire des chaînes de caractères.

Syntaxe

 
  char *gets(char *string)
  int   puts(char *string)
  char *fgets(char *string, int nombre, FILE *flot)
  int   fputs(char *string, FILE *flot)

Les fonctions gets, fgets renvoient la chaîne lue ou le pointeur NULL si fin de fichier. Les fonctions puts, fputs renvoient le nombre de caractères écrits ou EOF si erreur.

Exemple

 
#include <stdio.h>
main()
{
  char *mus1 = "Wolfgang Amadeus Mozart\n";
  char *mus2 = "Ludwig van Beethoven\n";
  char  buffer[BUFSIZ+1];
  FILE *f;
  if ((f = fopen("musiciens", "w")) == NULL) {
    perror("fopen");
    exit(1);
  }
  fputs(mus1, f); fputs(mus2, f);
  fclose(f);
  if ((f = fopen("musiciens", "r")) == NULL) {
    perror("fopen");
    exit(2);
  }
  while (fgets(buffer, sizeof(buffer), f))
     fputs(buffer, stdout);
  fclose(f);
  puts("\nExecution terminee.");
}

9.2.5 Lecture et écriture de blocs

Les fonctions fread et fwrite permettent de lire et d'écrire des blocs de données tels des structures ou des tableaux.

Syntaxe

 
size_t fread(void *p, size_t t, size_t n, FILE *f)
size_t fwrite(void *p, size_t t, size_t n, FILE *f)

Ces fonctions retournent le nombre de blocs traités. Utiliser les pseudo-fonctions feof et ferror pour tester la fin de fichier et une erreur d'entrée-sortie.

Exemple

 
#include <stdio.h>
#define NbElt(t) ( sizeof t / sizeof t[0] )
main() {
  typedef struct { int   n; float t[10]; char  c;
                 } Donnee;
  Donnee s1   = { 1, { 1.,  2., 3.}, 'a'};
  Donnee s2[] = { {4, {10., 32., 3.}, 'z'},
                  {5, { 2., 11., 2., 4.}, 'h'} };
  FILE *f, *f_sauve; Donnee s;
  if ((f = fopen("donnee", "w")) == NULL)
    perror("fopen"), exit(1);
  fwrite(&s1, sizeof(Donnee), 1, f);
  fwrite( s2, sizeof(Donnee), NbElt(s2), f);
  fclose(f);
  if ((f = fopen("donnee", "r")) == NULL ||
      (f_sauve = fopen("sauvegarde", "w")) == NULL)
    perror("fopen"), exit(2);
  fread(&s, sizeof(Donnee), 1, f);
  while (!feof(f)) {
    fwrite(&s, sizeof(Donnee), 1, f_sauve);
    fread(&s, sizeof(Donnee), 1, f); }
  fclose(f); fclose(f_sauve);
}

9.2.6 Accès direct

Par défaut, les fonctions précédentes travaillent en mode séquentiel. Chaque lecture ou écriture s'effectue à partir d'une position courante, et incrémente cette position du nombre de caractères lus ou écrits.

Les fonctions fseek et ftell permettent, respectivement, de modifier et récupérer la position courante.

 
int  fseek(FILE *f, long decalage, int position);
long ftell(FILE *f);

La fonction ftell retourne la position courante en octets.

La fonction fseek permet de la modifier :

Exemple

 
#include <stdio.h>
main(int argc, char **argv)
{
   FILE *f;
   void  usage(char *s);
 if (argc != 2)
     usage(argv[0]);
   if ((f = fopen(argv[1], "r")) == NULL) {
     perror("fopen");
     exit(2);
   }
   fseek(f, 0L, SEEK_END);
   printf("Taille(octets) : %d\n", ftell(f));
   fclose(f);
}
void  usage(char *s)
{
   fprintf(stderr, "usage : %s fichier\n", s);
   exit(1);
}

9.2.7 Entrées-sorties formatées

Les fonctions scanf, fscanf, sscanf et printf, fprintf, sprintf permettent d'effectuer des entrées-sorties de données avec conversions.

Syntaxe

 
int scanf(const char *format [, ...])
int fscanf(FILE *f, const char *format [, ...])
int sscanf(const char *buffer,
           const char *format [, ...])
int printf(const char *format [, ...])
int fprintf(FILE *f, const char *format [, ...])
int sprintf(const char *buffer,
            const char *format [, ...])

9.2.8 Fonctions printf, fprintf, sprintf

Le paramètre format désigne une chaîne de caractères comprenant :

Après les conversions effectuées, cette chaîne est reproduite :

Les spécifications de conversions portent successivement sur les arguments passés à la suite du paramètre format.

Une spécification de conversion est constituée du caractère %, suivie dans l'ordre :

Exemples

 
printf("|%d|\n", 1234);             |1234|
printf("|%+d|\n", 1234);            |+1234|
printf("|%10d|\n", 1234);           |      1234|
printf("|%x|\n", 0x56ab);           |56ab|
printf("|%#x|\n", 0x56ab);          |0x56ab|
printf("|%X|\n", 0x56ab);           |56AB|
printf("|%#X|\n", 0x56ab);          |0X56AB|
printf("|%f|\n",1.234567890123456789e5); |123456.789012|
printf("|%.4f|\n",1.234567890123456789e5); |123456.7890|
printf("|%15.4f|\n",1.234567890123456789e5);  |    123456.7890|
printf("|%e|\n",1.234567890123456789e5);              |1.234568e+05|
printf("|%.18e|\n",1.234567890123456789e5); ~~~~~~~~~~|1.234567890123456700e+05|
printf("|%.4g|\n",1.234567890123456789e-5);          |1.235e-05|
printf("|%.4g|\n",1.234567890123456789e-3);           |0.001235|

9.2.9 Fonctions scanf, fscanf, sscanf

Ces fonctions permettent d'effectuer des entrées formatées. Les données lues sont converties suivant les spécifications de conversions indiquées dans la chaîne format, puis stockées dans les arguments successifs fournis à sa suite. Ces arguments doivent être des pointeurs.

La valeur retournée correspond au nombre d'arguments correctement affectés. La chaîne format peut contenir :

Les données en entrée sont découpées en champs.

Chaque champ est défini comme une chaîne de caractères qui s'étend soit :

Une spécification de conversion est constituée du caractère % suivi dans l'ordre :

Remarques

Les arguments correspondant aux spécifications :

On peut faire précéder les spécifications d, i, o, x, u par la lettre h ou l pour référencer un short * ou un long *.

De même les spécifications e, f, g peuvent être précédées de la lettre l pour référencer un double *.

Exemples

 
#include <stdio.h>
main()
{
  int   i;
  float x, y;
  char  buffer[BUFSIZ];
  char *p = "12/11/94";
  int   jour, mois, annee;
 scanf("%d%f%f%*c", &i, &x, &y);
  printf("i = %d, x = %f, y = %f\n", i, x, y);
  scanf("%[^\n]%*c", buffer);
  while (!feof(stdin)) {
    fprintf(stderr, "%s\n", buffer);
    scanf("%[^\n]%*c", buffer);
  }
  sscanf(p, "%d/%d/%d", &jour, &mois, &annee);
  printf("jour  : %d\n", jour);
  printf("mois  : %d\n", mois);
  printf("annee : %d\n", annee);
}

9.2.10 Autres fonctions

La fonction freopen permet de redéfinir un flot déjà initialisé. Elle est principalement utilisée avec les flots stdin, stdout, stderr, ce qui correspond à une redirection d'entrées-sorties.

La fonction fflush permet de forcer le vidage de la mémoire tampon associée à un flot en sortie. Sur un flot en entrée l'effet est imprévisible.

Syntaxe

 
FILE *freopen(char *fichier, char *mode, FILE *flot);
int   fflush(FILE *flot);

Exemple

 
#include <stdio.h>
main(int argc, char **argv)
{
  void usage(char *s);
  if (argc != 2)
    usage(argv[0]);
  if (freopen(argv[1], "w", stdout) == NULL) {
    perror("freopen");
    exit(2);
  }
  printf("Ce message est redirige ");
  printf("dans le fichier ");
  printf("dont le nom est ");
  printf("passe en argument.\n");
}
void usage(char *s)
{
  fprintf(stderr, "usage : %s fichier\n", s);
  exit(1); }


Pr. Marc BUFFAT
buffat@ufrmeca.univ-lyon1.fr
2004-12-01