Les entrées-sorties Les entrées-sorties Couches accessibles par programmation Appels système Système d exploitation périphériques Disque dur Benoît Charroux - entrées / sorties - Septembre 98-2
La bibliothèque d entrées-sorties standard Masquage des appels systèmes à l aide d un mécanisme de cache (mémoire tampon) : bonne portabilité ; problèmes d incohérence avec le contenu du disque existence de fonctions pour forcer l écriture des caches sur le disque. Le fichier stdio.h (#include <stdio.h>) contient : des constantes : NULL, EOF (fin de fichier), _NFILE (nombres de fichiers manipulables), BUFSIZ (taille du tampon associé), stdin (entrée standard), stdout (sortie standard), stderr (sortie erreur standard) ; la définition du type opaque FILE (un pointeur de type FILE sera utilisé par toutes les fonctions). Benoît Charroux - entrées / sorties - Septembre 98-3 L ouverture des fichiers
Ouverture d un fichier FILE* fopen( const char* ref, const char* mode ) ; mode d ouverture : "r" (lecture) ; Mise à 0 de la taille d un fichier existant. "w" (écriture avec troncature ou création) ; "a" (écriture en fin de fichier et/ou création) ; Création d un nouveau fichier s il n existe pas "r+" (lecture et écriture sans création ni troncature) ; "w+" (lecture et écriture avec création ou troncature ) ; "a+" (lecture n importe où, écriture en fin de fichier et création). Benoît Charroux - entrées / sorties - Septembre 98-5 Exemple d ouverture d un fichier Règle : toujours tester le retour de fopen (NULL en cas d échec à l ouverture). FILE* ptrfile = fopen( "fichier.txt", "r" ) ; if( ptrfile == NULL ){ printf( "Impossible d ouvrir le fichier\n" ) ; exit( 1 ) ; Benoît Charroux - entrées / sorties - Septembre 98-6
Les fichiers textes et les fichiers binaires Un fichier binaire est un fichier où les caractères spéciaux (fin de lignes, nouvelle ligne, ) ne sont pas interprétés : lecture d un fichier texte interprétation des caractères de fin de ligne, lecture d un fichier binaire obtention du contenu brut du disque. Exemple de lecture d un fichier : Bidon.c Contenu du disque : \r\n sauvegarde édition Mode binaire : "r+b", "w+b", "a+b" ; Exemple : FILE* ptrfile = fopen( "fichier.bin", "r+b" ) ; Lecture d une ligne en mode texte : Lecture en mode binaire : \r\n Benoît Charroux - entrées / sorties - Septembre 98-7 La fermeture d un fichier entraîne : La fermeture d un fichier int fclose( FILE* ptrfile ) ; le transfert des données de la mémoire tampon dans les caches du système ; la libération de la mémoire associée à ptrfile. Valeur de retour : 0 en cas de succès ; EOF en cas d échec. Le fermeture est automatique lors d un appel à la fonction exit. Conseil : fermer les fichiers le plus tôt possible. Exemple : FILE* ptrfile = fopen( "fichier.bin", "r+b" ) ; fclose( ptrfile ) ; Benoît Charroux - entrées / sorties - Septembre 98-8
L écriture dans des fichiers L écriture dans un fichier L écriture ne se fait pas directement sur le disque mais dans une mémoire tampon ; en cas d échec les fonctions d écriture retourne EOF ou une valeur < 0 ; l écriture d un caractère c : int putc( int c, FILE* ptrfile ) ; /* macro */ int fputc( int c, FILE* ptrfile ) ; /* fonction */ l écriture d une chaîne de caractères s (sans écriture du caractère de fin de chaîne) : int fputs( char* s, FILE* ptrfile ) ; l écriture formatée : int fprintf( FILE* ptrfile, const char* format, ) ; l écriture par blocs : int fwrite( void* ptr, size_t taille, size_t nbelem, FILE* ptrfile ) ; écrit nbelem de taille «taille» pointés par ptr. Benoît Charroux - entrées / sorties - Septembre 98-10
Exemple d écriture dans un fichier int main( int argc, char* argv[] ){ if( argc!= 2 ){ fprintf( stderr, "Erreur d arguments" ) ; Ligne de commande : exit( 2 ) ; >main noms.txt FILE* ptrfile = fopen( argv[1], "w" ) ; if( ptrfile == NULL ){ fprintf( stderr, "Impossible d ouvrir le fichier %s", argv[1] ) ; exit( 2 ) ; noms.txt nom 1 : for( int i=0; i<10; i++ ){ nom 2 : fprintf( ptrfile, "nom %d : %s\n", i, nom[i] ) ;... Benoît Charroux - entrées / sorties - Septembre 98-11 L écriture d un tableau de structures dans un fichier typedef struct s{ char nom[ 50 ] ; int age ; PERSONNE ; PERSONNE tab[ 10 ] ; fwrite( tab, sizeof( PERSONNE), 10, ptrfile ) ; Le fichier n est pas portable! Benoît Charroux - entrées / sorties - Septembre 98-12
La lecture dans des fichiers La lecture dans un fichier 1/2 La lecture ne se fait pas directement sur le disque mais dans une mémoire tampon ; la lecture d un élément provoque un déplacement dans le fichier de la taille de cet élément ; la lecture d un caractère : int getc( int c, FILE* ptrfile ) ; /* macro */ int fputc( int c, FILE* ptrfile ) ; /* fonction */ la valeur de retour EOF indique la fin du fichier ou erreur ; la lecture d une chaîne de caractères de taille maximale taille-1 (un caractère nul est rajouté à la fin) : char* fgets( char* s, int taille, FILE* ptrfile ) ; la lecture s arrête avant taille-1 si un caractère nul est rencontré (le caractère nul est recopié dans la chaîne) ; s pointe sur la chaîne lue ou sur NULL sinon. Benoît Charroux - entrées / sorties - Septembre 98-14
La lecture dans un fichier 2/2 La lecture formatée (retourne EOF en fin de fichier ou en cas d erreur) : la lecture par blocs : int fscanf( FILE* ptrfile, const char* format, ) ; int fread( void* ptr, size_t taille, size_t nbelem, FILE* ptrfile ) ; lit nbelem de taille «taille», le résultat est pointé par ptr, le nombre d éléments lus est renvoyé par le fonction. int feof( FILE* ptrfile ) ; retourne une valeur non nulle si la fin de fichier à été atteinte lors d une lecture. Benoît Charroux - entrées / sorties - Septembre 98-15 Exemple de lecture dans un fichier Lecture d un fichier texte ligne à ligne : char s[ 1024 ] ; while( fgets( s, 1024, ptrfile )!= NULL ){ Benoît Charroux - entrées / sorties - Septembre 98-16
Les limitation de scanf : Exemple d utilisation de fgets 1/2 int i ; scanf( "%d", &i ) ; /* potentiellement dangereux */ Si l utilisateur tape 1O0 à la place de 100, il n y a pas d erreur et i vaut 1! Caractère O. char chaine[ 50 ] ; scanf( "%s", chaine ) ; /* potentiellement dangereux */ Si l utilisateur tape plus de 50 caractères! Benoît Charroux - entrées / sorties - Septembre 98-17 Exemple d utilisation de fgets 2/2 Conseil : utilisez fgets à la place de scanf. char chaine[ 50 ] ; int i ; if( sscanf( chaine, "%d", &i ) == EOF ){ printf( "Erreur\n" ) ; exit( 2 ) ; Benoît Charroux - entrées / sorties - Septembre 98-18
La lecture d un tableau de structures dans un fichier typedef struct s{ char nom[ 50 ] ; int age ; PERSONNE ; PERSONNE tab[ 10 ] ; if( fread( tab, sizeof( PERSONNE), 10, ptrfile )!= 10*sizeof(PERSONNE) ){ printf( "Erreur\n" ) ; exit( 2 ) ; Le fichier doit avoir été rempli avec fwrite sur le même système! Benoît Charroux - entrées / sorties - Septembre 98-19 Se déplacer dans un fichier
Se déplacer dans un fichier int fseek( FILE* ptrfile, long int offset, int origine ) ; se déplace dans un fichier de offset octets par rapport à origine ; valeurs possibles pour origine : SEEK_CUR (possition courante) ; SEEK_SET (début de fichier) ; SEEK_END (fin du fichier). retourne la position (en nombre d octets) dans le fichier après déplacement. Comment connaître la taille d un fichier? int taille ; taille = fseek( ptrfile, 0, SEEK_END ) ; Benoît Charroux - entrées / sorties - Septembre 98-21 La gestion du tampon
Créer un nouveau tampon int setvbuf( FILE* ptrfile, char* tampon, int mode size_t taille ) ; permet d associer un nouveau tampon à chaque fichier, où : tampon est l adresse du tampon ; taille est sa taille ; mode est le critère de vidage : _IOFBF (quand le tampon est plein) ; _IOLBF (quand le tampon est vide) ; _IONBF (systématiquement). int fflush( FILE* ptrfile ) ; permet de vider le tampon (la valeur NULL comme paramètre correspond à une demande de vidage de tous les fichiers actuellement ouvert). Benoît Charroux - entrées / sorties - Septembre 98-23 Vider les tampons int fflush( FILE* ptrfile ) ; permet de vider le tampon si ptrfile = NULL : demande de vidage de tous les fichiers actuellement ouvert. int i, j ; scanf( "%d", &i ) ; scanf ( "%d", &j ) ; La 2ième lecture n est pas réalisée car il reste le caractère \n dans le tampon! int i, j ; scanf( "%d", &i ) ; scanf ( "%d", &j ) ; Benoît Charroux - entrées / sorties - Septembre 98-24