140 likes | 242 Views
Programare in limbajul C – Cursul 13 Intrare şi ieşire Prof. univ. dr. Constantin Popescu. Agenda. Pointeri de fişier şi funcţia fopen Intrare / ieşire cu pointeri de fişier Stream-uri predefinite Închiderea fişierelor. Pointeri de fişier şi funcţia fopen (1).
E N D
Programare in limbajul C – Cursul 13Intrare şi ieşireProf. univ. dr. Constantin Popescu
Agenda • Pointeri de fişier şi funcţia fopen • Intrare/ieşire cu pointeri de fişier • Stream-uri predefinite • Închiderea fişierelor
Pointeri de fişier şi funcţia fopen (1) • O variabilă pentru stocarea unui pointer de fişier se declară astfel: FILE *fp; • Tipul FILE este predefinit în stdio.h. Este o structură de date care păstrează informaţiile de care are nevoie biblioteca de intrare - ieşire pentru a ţine evidenţa fişierului. • Dacă citim din două fişiere în acelaşi timp probabil că avem nevoie de doi pointeri de fişier: FILE *fp1, *fp2; • Dacă dintr-un fişier citim şi în altul scriem s-ar putea să fie nevoie să declarăm un pointer pentru fişierul de intrare (input) şi unul pentru fişierul de ieşire (output): FILE *ifp, *ofp; • Pentru a deschide fişierul input.dat pentru citire putem apela funcţia fopen astfel: ifp = fopen("input.dat", "r"); • Şirul pentru modul de deschidere "r" indică citire (read). Pentru scriere folosim "w".
Moduri de deschidere a fisierelor SimbolSemnificatie r deschide pentru citire w deschide pentru scriere a deschide pentru adaugare r+ deschide un fisier existent pentru actualizare (citire si scriere) w+ deschide un fisier nou pentru actualizare a+ deschide pentru actualizare la sfirsitul fisierului b se poate adauga optional la sfirsitul modurilor de acces de mai sus, pentru prelucrare in mod binar
Pointeri de fişier şi funcţia fopen (2) • Pentru a deschide fişierul output.dat pentru a scrie în el folosim funcţia: ofp = fopen("output.dat", "w"); • Fiecare apel al funcţiei fopen va fi urmat de un test aşa cum facem mai jos: ifp = fopen("input.dat", "r"); if(ifp == NULL) { printf("nu pot deschide fisierul\n"); exit sau return } • Este o practică obişnuită de a apela funcţia fopen şi a face atribuirea pointerului returnat în cadrul testului: if((ifp = fopen("input.dat", "r")) == NULL) { printf("nu pot deschide fisierul \n"); exit sau return }
Intrare ieşire cu pointeri de fişier (1) • Funcţia asociată lui printf este fprintf, iar argumentul suplimentar (pointerul de fişier) se pune primul. • Pentru a scrie un şir de caractere în fişierul output.dat pe care l-am deschis în secţiunea precedentă, putem folosi apelul: fprintf(ofp, "Hello, world!\n"); • Funcţia asociată lui getchar este getc, iar pointerul de fişier este singurul ei argument. • Pentru a citi un caracter din fişierul input.dat deschis în secţiunea precedentă, putem folosi apelul: int c; c = getc(ifp); • Funcţia asociată lui putchar este putc, iar pointerul de fişier este ultimul ei argument. Pentru a scrie un caracter în fişierul output.dat, putem folosi apelul: putc(c, ofp);
Intrare ieşire cu pointeri de fişier (2) • Putem scrie o funcţie fgetline care citeste dintr-un fişier: #include <stdio.h> /* Citeste o linie din fp, */ /*copiind linia in tabloul line(dar nu mai multe de max caractere). */ /* Terminatorul de linie \n nu va fi plasat in tablou. */ /* Se returneaza lungimea liniei sau 0 pentru liniile goale, sau EOF pentru sfarsit de fisier. */ int fgetline(FILE *fp, char line[], int max) { int nch = 0; int c; max = max - 1;/* lasam loc pentru '\0' */ while((c = getc(fp)) != EOF){ if(c == '\n') break; if(nch < max){ line[nch] = c; nch = nch + 1; } } if(c == EOF && nch == 0) return EOF; line[nch] = '\0'; return nch; } • Acum putem citi o linie din ifp: char line[MAXLINE]; ... fgetline(ifp, line, MAXLINE);
Stream-uri predefinite (1) • Pe lângă pointerii de fişier deschişi explicit prin apelul funcţiei fopen, există trei stream-uri predefinite: • stdin este un pointer de fişier constant ce corespunde intrării • stdout este un pointer de fişier constant ce corespunde ieşirii • stderr este conectat implicit la ecran. Diferenţa este că stderr nu este redirectat când redirectăm ieşirea standard a unui program. • De exemplu, sub Unix sau MS-DOS, când apelăm un program sub forma: program > nume_fisier • Tot ceea ce se tipăreşte la stdout este redirectat în fişierul specificat în linia de comandă, dar ceea ce se tipăreşte la stderr va ajunge pe ecran. • De fapt stderr vrea să fie "ieşirea standard pentru erori"; mesajele de eroare tipărite la acest stream nu vor dispărea într-un fişier.
Stream-uri predefinite (2) • De exemplu, un mod mai realist de a tipări mesaje de eroare atunci când nu putem deschide un fişier ar fi: if((ifp = fopen(nume_fisier, "r")) == NULL) { fprintf(stderr, "nu pot deschide fisierul %s\n", nume_fisier); exit sau return } • Unde nume_fisier este o variabilă şir de caractere care indică numele fişierului ce trebuie deschis. • Nu numai că mesajul este tipărit la stderr, dar este şi mai informativ acest mesaj pentru că este menţionat şi numele fişierului ce nu a putut fi deschis.
Stream-uri predefinite (3) Exemplu: #include <stdio.h> int main () { FILE* ifp; if((ifp = fopen("test.dat", "r")) == NULL) { fprintf(stderr, "nu pot deschide fisierul \n"); return 1; } return 0; }
Cu toate că putem avea deschise simultan mai multe fişiere, există o limită asupra numărului de fişiere deschise la un moment dat. Dacă programul deschide mai multe fişiere, atunci ar trebui să închidem fişierele asupra cărora am terminat de operat. Altfel biblioteca standard de intrare - ieşire ar putea să epuizeze resursele pe care le foloseşte pentru a ţine evidenţa fişierelor deschise. Închiderea unui fişier implică doar apelul funcţiei fclose cu un pointer de fişier ca argument: fclose(fp); Apelul funcţiei fclose determină (dacă fişierul a fost deschis pentru scriere): scrierea în fişier a datelor care au fost păstrate în buffer eliberarea resurselor folosite de sistemul de operare (şi de biblioteca C). Dacă uităm să închidem fişierul, acesta va fi închis automat când programul se termină. Închiderea fişierelor
Exemplu: citirea datelor dintr-un fişier • Presupunem că avem un fişier ce conţine numere sub formă tabelară: 1 2 34 5 6 78 9 10 112 • Presupunem că vrem să cititm aceste numere într-un tablou. • Tabloul va fi de fapt un tablou de tablouri sau un tablou multidimensional. • Putem scrie codul pentru a îndeplini această sarcină prin alipirea câtorva secvenţe pe care le-am scris deja: funcţia getline şi funcţia getwords.
Exemplu: citirea datelor dintr-un fişier #define MAXLINIE 100 #define MAXLINII 10 #define MAXCOL 10 int array[MAXLINII][MAXCOL]; char *filename = "input.dat"; FILE *ifp; char line[MAXLINIE]; char *words[MAXCOL]; int n, i, nrows = 0; ifp = fopen(filename, "r"); if(ifp == NULL){ fprintf(stderr,"nu pot deschide fisierul %s\n",filename); exit(EXIT_FAILURE); } while(fgetline(ifp, line, MAXLINIE) != EOF){ if(nrows >= MAXLINII) { fprintf(stderr, "prea multe linii\n"); exit(EXIT_FAILURE); } n = getwords(line, words, MAXCOL); for(i = 0; i < n; i++) array[nrows][i] = atoi(words[i]); nrows++; }
Exemplu #include <stdio.h> int main () { char in_name[80],out_name[80]; FILE *instream, *outstream; int ch; printf(“Fisierul sursa"); scanf("%79s", in_name); if((instream = fopen(in_name, "r")) == NULL) { fprintf(stderr, “nu se poate deschide fisierul %s ", in_name); return 1; } printf(“Fisierul destinatie"); scanf("%79s", out_name); if((outstream = fopen(out_name, "w")) == NULL) { fprintf(stderr, “nu se poate scrie in fisierul %s ", out_name); return 1; } while((ch=fgetc(instream))!=EOF) fputc(ch, outstream); fclose(instream); fclose(outstream); return 0; }