46 On désigne le fichier destination par son handle (celui rendu par open), l'a

46 On désigne le fichier destination par son handle (celui rendu par open), l'adresse du bloc à écrire et la taille (en octets) de ce bloc. Le nombre d'octets écrits est retourné, -1 si erreur. int read(int handle, void *bloc, unsigned taille); lit dans le fichier désigné par son handle, et le met dans le bloc dont on donne l'adresse et la taille. La fonction retourne le nombre d'octets lus (<=taille, <si fin du fichier en cours de lecture, 0 si on était déjà sur la fin du fichier, -1 si erreur). int eof(int handle) dit si on se trouve (1) ou non (0) sur la fin du fichier. Lorsque l'on ne se sert plus du fichier, il faut le fermer (obligatoire pour que le fichier soit utilisable par le système d'exploitation, entre autre mise à jour de sa taille : int close(int handle) fermeture, rend 0 si ok, -1 si erreur. Le fichier peut être utilisé séquentiellement (le "pointeur de fichier" est toujours placé derrière le bloc que l'on vient de traiter, pour pouvoir traiter le suivant). Pour déplacer le pointeur de fichier en n'importe que autre endroit, on appelle la fonction : long lseek(int handle, long combien, int code); déplace le pointeur de fichier de combien octets, à partir de : début du fichier si code=0, position actuelle si 1, fin du fichier si 2. La fonction retourne la position atteinte (en nb d'octets), -1L si erreur. long filelength(int handle); rend la taille d'un fichier (sans déplacer le pointeur de fichier). Exemple : copie de fichier (les noms de fichiers sont donnés en argument du programme) #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys\stat.h> #define taillebloc 1024 int main(int argc,char *argv[]) { int source, destination; char buffer[taillebloc]; int nb_lus,nb_ecrits; if (argc!=3) {puts("erreur arguments");return(1);} if((source=open(argv[1],O_RDONLY|O_BINARY))<0) {puts("erreur ouverture");return(2);} if((destination=open(argv[2], O_WRONLY| O_CREAT| O_TRUNC| O_BINARY, S_IREAD| S_IWRITE| S_IEXEC))<0) {puts("erreur ouverture");return(2);} do { nb_lus=read(source,(char *)buffer,taillebloc); if (nb_lus>0) nb_ecrits= write(destination,(char*)buffer, nb_lus); } 47 while ((nb_lus==taillebloc)&&(nb_ecrits>0)); close(source); close(destination); return(0); } Fichiers bufférisés Les opérations d'entrée / sortie sur ces fichiers se font par l'intermédiaire d'un "buffer" (bloc en mémoire) géré automatiquement. Ceci signifie qu'une instruction d'écriture n'impliquera pas une écriture physique sur le disque mais dans le buffer, avec écriture sur disque uniquement quand le buffer est plein. Les fichiers sont identifiés non par un entier mais par un pointeur sur une structure FILE (définie par un typedef dans stdio.h). Les fonctions disponibles (prototypées dans stdio.h) sont : FILE *fopen(char *nomfic, char *mode) : ouvre le fichier, suivant le mode : r (lecture seule), w (écriture, si le fichier existe il est d'abord vidé), a (append : écriture à la suite du contenu actuel, création si inexistant), r+ (lecture et écriture, le fichier doit exister), w+ (lecture et écriture mais effacement au départ du fichier si existant), a+ (lecture et écriture, positionnement en fin de fichier si existant, création sinon). Sur PC, on peut rajouter t ou b au mode pour des fichiers texte (gestion des CR/LF, option par défaut) ou binaires, ou le définir par défaut en donnant à la variable _fmode la valeur O_TEXT ou O_BINARY. fopen rend un identificateur (ID) qui nous servira pour accéder au fichier. En cas d'erreur, le pointeur NULL est retourné, le type d'erreur est donné dans une variable errno, détaillée dans errno.h. La fonction void perror(char *s mess) affichera le message correspondant à l'erreur, en général on lui donne le nom du fichier. int fread(void *bloc, int taille, int nb, FILE *id) : lit nb éléments dont on donne la taille unitaire en octets, dans le fichier désigné par id, le résultat étant stocké à l'adresse bloc. La fonction rend le nombre d'éléments lus (<nb si fin de fichier), 0 si erreur. int fwrite(void *bloc, int taille, int nb, FILE *id) : écriture du bloc sur fichier, si le nombre rendu est différent de nb, il y a eu erreur (tester ferror ou errno). int fclose(FILE *id) : ferme le fichier, en y recopiant le reste du buffer si nécessaire. Cette fonction est obligatoire pour être sur d'avoir l'intégralité des données effectivement transférées sur le disque. Retourne 0 si tout s'est bien passé. int fflush(FILE *id) : transfère effectivement le reste du buffer sur disque, sans fermer le fichier (à appeler par exemple avant une instruction qui risque de créer un "plantage"). int fseek(FILE *id, long combien, int mode) : déplace le pointeur de fichier de combien octets, à partir de : début du fichier (mode=0), position actuelle (mode=1) ou fin du fichier (mode=2). Retourne 0 si tout c'est bien passé. Cette fonction n'est utilisable que si l'on connaît la taille des données dans le fichier (impossible d'aller directement à une ligne donnée d'un texte si on ne connaît pas la longueur de chaque ligne). int feof(FILE *id) dit si on est en fin de fichier ou non (0). Les fichiers bufférisés permettent aussi des sorties formatées : 48 au niveau caractère : char fgetc(FILE *id), char fputc(char c, FILE *id), et même char ungetc(char c, FILE *id) qui permet de "reculer" d'un caractère. Cette fonction correspond donc à {fseek(id,- 1,1);c=fgetc(id)}. au niveau chaîne de caractères : char *fgets(char *s, int max, FILE *id) : lit une chaîne en s'arrêtant au \n ou à max-1 caractères lus, résultat dans la zone pointée par s, et retour du pointeur s ou NULL si erreur. char fputs(char *s, FILE *id) : écrit la chaîne dans le fichier sans ajouter de \n, rend le dernier caractère écrit ou EOF si erreur. int fprintf(FILE *id, char *format, listearguments) : rend le nb d'octets écrits, ou EOF si erreur. Les \n sont transformés en CR/LF si fichier en mode texte (spécifique PC). int fscanf(FILE *id, char *format, listeadresses) : rend le nombre de variables lues et stockées, 0 si erreur). En général, on utilise les fichiers bufférisés : - Soit en accès direct, en lecture et écriture, avec tous les éléments de même type et même taille (souvent une structure, en format binaire), ceci permettant d'accéder directement à un élément donné (le 48ème, le précédent, l'avant dernier...). - Soit en accès séquentiel, avec des éléments de type différent, tous formatés sous forme ASCII, en lecture seule ou écriture seule (il est peu probable que le remplacement d'un élément se fasse avec le même nombre d'octets et nécessiterait un décalage dans le fichier), ces fichiers seront compréhensibles par n'importe quel autre programme (éditeur de texte, imprimante...). Un tel fichier s'utilise comme l'écran et le clavier, par des fonctions similaires. Exercice (agenda) : modifier l'agenda de l'exercice tel en permettant de sauver les données sur disque. On utilisera un fichier binaire à accès direct. On pourra ensuite apporter les améliorations suivantes : recherche rapide par dichotomie sans lire tout le fichier (en le supposant classé par ordre alphabétique), création de fichiers index classés alphabétiquement sur les noms, département et ville pour accès rapide par dichotomie, les autres se faisant par recherche séquentielle, avec possibilité d'ajout, suppression, édition du fichier. #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <conio.h> /* définitions des types et variables associées */ enum champs {nom,prenom,num,rue,cp,ville,tel}; char *nomchamp[7]={"Nom","Prénom","Numéro","Rue", "Code Postal","Ville","Tel"}; typedef struct { char nom[15]; char prenom[20]; int num; char rue[60]; long codepostal; char ville[20]; 49 char tel[15]; } fiche; #define taille sizeof(fiche) typedef fiche *ptrfiche; /* définitions des fonctions de recherche, regroupées dans un tableau */ fiche *rech_nom(fiche *,char *); fiche *rech_prenom(fiche *,char *); fiche *rech_num(fiche *,char *); fiche *rech_rue(fiche *,char *); fiche *rech_cp(fiche *,char *); fiche *rech_ville(fiche *,char *); fiche *rech_tel(fiche *,char *); fiche *rech_nom(fiche *,char *); typedef ptrfiche (*ptrfonction)(ptrfiche,char*); ptrfonction tabfonction[7]= {rech_nom, rech_prenom, rech_num, rech_rue, rech_cp, rech_ville, rech_tel}; /* variables globales */ FILE *fic; /* fichier de données */ char *nomfic="agenda.dat"; int nb; /* nb de fiches dans le fichier */ void init(void) /* ouvre le fichier, détermine le nb de fiches de fic */ { if ((fic=fopen(nomfic,"a+b"))==NULL) { puts("ouverture impossible du fichier de données"); exit(1); } fseek(fic,0,2); nb=(int)ftell(fic)/taille; printf("%d fiches présentes dans l'agenda\n",nb); } void ajouter(void) { char lig[40]; fiche f; printf("nom ? "); gets(f.nom); printf(" prénom ? "); gets(f.prenom); printf(" Numero ? "); gets(lig); sscanf(lig,"%d",&(f.num)); printf(" rue ? "); gets(f.rue); printf(" code postal ? "); gets(lig); sscanf(lig,"%ld",&(f.codepostal)); printf(" ville ? "); gets(f.ville); printf("n° de téléphone ? "); gets(f.tel); fseek(fic,0L,2); if(fwrite(&f,taille,1,fic)!=1) { puts("impossible d'ajouter cette fiche au fichier "); exit(0); } 50 nb++; } void affiche(fiche *f) { if((f!=NULL)&&(f->nom[0])) printf("%s %s\n%d, %s\n%ld %s\nTel : %s\n",f->nom, f-> prenom, f->num, f->rue,f->codepostal,f->ville,f->tel); else printf("fiche inconnue\n"); } int idem(char *s1,char *s2) /* compare deux chaines, dit si elles sont égales (1), ou non (0). On considère égales majuscules et minuscules. Une des chaines peut se terminer par *, on supposera identique si tout ce qui précède l'* était identique */ { for(;;) { if (((!*s1)&&(!*s2))||(*s1=='*')||(*s2=='*')) return(1); if ((toupper(*s1)!=toupper(*s2))||(!*s1)||(!*s2)) return(0); s1++;s2++; } } fiche *rech_nom(fiche *pf,char *n) { int nblu; fseek(fic,0L,0); do nblu=fread(pf,taille,1,fic); while ((nblu==1)&&(!idem(pf->nom,n))); if (nblu==1) return(pf); else return(NULL); } /* les autres recherches sont à continuer */ int choix(void) { char lig[40]; enum champs i,rep; for (i=nom;i<=tel;i++) printf("%d:%s ",i,nomchamp[i]); printf("\nou -1 pour quitter. Type de recherche désirée ? "); uploads/Litterature/ syntaxe-c10.pdf

  • 36
  • 0
  • 0
Afficher les détails des licences
Licence et utilisation
Gratuit pour un usage personnel Attribution requise
Partager