120 likes | 266 Views
Programare in limbajul C – Cursul 18 Biblioteca standard de intrare ieşire (stdio) Prof. univ. dr. Constantin Popescu. Agenda. Deschiderea şi închiderea fişierelor (fopen, fclose) Introducerea şi afişarea caracterelor (getchar, putchar) Introducerea şi afişarea liniilor (fgets, fputs etc.)
E N D
Programare in limbajul C – Cursul 18Biblioteca standard de intrare ieşire (stdio)Prof. univ. dr. Constantin Popescu
Agenda • Deschiderea şi închiderea fişierelor (fopen, fclose) • Introducerea şi afişarea caracterelor (getchar, putchar) • Introducerea şi afişarea liniilor (fgets, fputs etc.) • Intrare şi ieşire aleatoare (fread, fwrite) • EOF şi erori • Operaţii asupra fişierelor (remove, rename)
Deschiderea şi închiderea fişierelor • Funcţia fopen deschide un fişier (sau un alt obiect de intrare-ieşire, dacă sistemul de operare permite tratarea dispozitivelor ca şi cum ar fi fişiere) şi retunează un stream (FILE*) ce poate fi folosit pentru operaţiile de intrare-ieşire. • Prototipul funcţiei fopen este: FILE *fopen(char *filename, char *mode) • Modurile în care poate fi deschis un fişier sunt: • r - deschidere pentru citire • w - deschidere pentru scriere (fişierul va fi trunchiat, dacă există) • a - deschidere pentru scriere (datele vor fi scrise la sfârşitul fişierului, dacă există) • Şirul de caractere care descrie modul de deschidere poate să mai conţină două caractere opţionale: • + deschide fişierul atât pentru citire cât şi pentru scriere • b deschide fişierul pentru intrare-ieşire binară
Introducerea şi afişarea caracterelor • Când citim caractere folosind funcţiile din biblioteca standard putem folosi funcţia ungetc funcţie care întoarce în stream un caracter citit şi îl face disponibil pentru apeluri ulterioare ale funcţiei getc (sau alte funcţii de citire). • Prototipul acestei funcţii este: int ungetc(int c, FILE *fp) • unde c este caracterul ce va fi întors în stream-ul fp. • De exemplu, mai jos dăm o secvenţă de cod care citeşte cifre dintr-un stream (şi le converteşte în numărul întreg corespunzător), oprindu-se la primul caracter non-cifră care este lăsat în stream-ul de intrare: #include <ctype.h> int c, n = 0; while((c = getchar()) != EOF && isdigit(c)) n = 10 * n + (c - '0'); if(c != EOF) ungetc(c, stdin);
Introducerea şi afişarea liniilor (1) • Funcţia: char *gets(char *line) • citeşte următoarea linie (până la următorul caracter \n) din intrarea standard şi plasează caract. în tabloul indicat de line. • Funcţia returnează un pointer la linia citită (returnează acelaşi pointer care i-a fost transmis) sau pointerul null în cazul în care am ajuns la sfârşitul fişierului. • Funcţia char *fgets(char *line, int max, FILE *fp) • Citeşte următoarea linie de intrare din stream-ul fp şi plasează caract., inclusiv caracterul \n, în tabl. de caract. pointat de line. • Al doilea argument, max, indică numărul maxim de caractere ce vor fi scrise în tablou şi de obicei va fi dimensiunea tabloului. • La fel ca şi funcţia gets, funcţia fgets returnează un pointer la linia citită sau un pointer null dacă este întâlnit sfârşitul fişierului.
Introducerea şi afişarea liniilor (2) • Funcţia: int puts(char *line) • scrie şirul de caractere indicat de line în ieşirea standard şi scrie un caracter \n pentru a-l termina. • Funcţia returnează o valoare ne-negativă (nu ne interesează acea valoare) dacă nu apare nici o eroare. • Altfel returnează EOF. • Funcţia int fputs(char *line, FILE *fp) • scrie şirul de caractere indicat de line în stream-ul fp. • La fel ca şi puts, fputs returnează o valoarea ne-negativă sau EOF dacă a apărut o eroare. • Spre deosebire de puts, fputs nu adaugă automat caracterul \n.
Intrare şi ieşire aleatoare (1) • Câteodată trebuie să citim blocuri de caractere, fără a le trata ca o "linie"şi fără a le interpreta aşa cum face scanf. • Prototipul funcţiei fread este: size_t fread(void *buf, size_t sz, size_t n, FILE *fp) • Prototipul funcţiei fwrite este: size_t fwrite(void *buf, size_t sz, size_t n, FILE *fp) • Pe lângă faptul că se pot citi "blocuri" de caractere, cu funcţiile fread şi fwrite se pot executa operaţii de intrare-ieşire "binare". • De exemplu, dacă avem un tablou de întregi: int array[N]; • putem scrie întreg conţinutul tabloului cu apelul: fwrite(array, sizeof(int), N, fp); • Acest apel va scrie conţinutul tabloului octet cu octet; se va face copierea unui bloc de octeţi din memorie la stream-ul de ieşire ceea ce diferă de modul de operare al funcţiei printf când este folosit specificatorul de format %d.
Intrare şi ieşire aleatoare (2) • Din moment ce unii octeţi din tabloul de întregi pot avea aceeaşi valoare ca şi caracterul \n, stream-ul va trebui deschis cu funcţia fopen în mod binar "wb". • Ulterior se pot citi aceşti întregi apelând funcţia fread(array, sizeof(int), N, fp); • Dacă avem o variabilă de tip structură: struct St x; • Se poate scrie toată această variabilă printr-un singur apel de forma: fwrite(&x, sizeof(struct St), 1, fp); • Si se poate citi prin apelul: fread(&x, sizeof(struct St), 1, fp);
EOF şi erori (1) • Când o funcţie returnează EOF spunem de obicei că am ajuns la "sfârşitul fişierului”. • Dar pot fi alte cauze care determină returnarea acestor valori, de exemplu erorile de intrare-ieşire. • Când vrem să facem distincţie între sfârşitul de fişier şi erori, putem folosi funcţiile feof şi ferror. • Funcţia feof(fp) returnează o valoare nenulă (adică "true") dacă a fost întâlnit sfârşitul de fişier şi funcţia ferror(fp) returnează o valoare nenulă dacă a apărut o eroare. • Nu putem scrie o secvenţă de genul: while(!feof(fp)) fgets(line, max, fp); • Trebuie să folosim o secvenţa ca şi cea de mai jos pentru a citi toate liniile dintr-un fişier: while(fgets(line, max, fp) != NULL)
EOF şi erori (2) • Cel mai simplu mesaj de eroare este de forma: fp = fopen(filename, "r"); if(fp == NULL){ fprintf(stderr, "nu pot deschide fisierul\n"); return; } • sau while(fgets(line, max, fp) != NULL) { ... procesez intrarea ... } if(ferror(fp)) fprintf(stderr, "am intalnit o eroare\n"); • sau fprintf(ofp, "%d %d %d\n", a, b, c); if(ferror(ofp)) fprintf(stderr, "erori la scriere\n");
EOF şi erori (3) • Un exemplu mai complet de a raporta eşecul operaţiei de deschidere a unui fişier este: #include <stdio.h> /* pentru fopen */ #include <errno.h> /* pentru errno */ #include <string.h> /* pentru strerror */ fp = fopen(filename, "r"); if(fp == NULL) { fprintf(stderr, "nu pot deschide %s pentru citire: %s\n",filename, strerror(errno)); return; } • Variabila errno este una globală, declarată în <errno.h>, care poate conţine un cod numeric ce indică motivul pentru care o operaţie de intrare-ieşire a eşuat. • Funcţia strerror transformă codul errno într-un şir de caractere care descrie eroarea.
Operaţii asupra fişierelor • Un fişier se poate şterge prin apelul funcţiei int remove(char *filename) • Numele unui fişier se poate schimba cu ajutorul funcţiei int rename(char *oldname, char *newname) • Ambele funcţii returnează zero dacă reuşesc să execute operaţia şi o valoare nenulă dacă eşuează. • Nu există funcţii standard C pentru lucrul cu directori (de exemplu listarea conţinutul sau creare lor). • Pe multe sisteme vom întâlni funcţii cum sunt mkdir pentru crearea directorilor şi rmdir pentru ştergerea lor şi o suită de funcţii opendir, readdir şi closedir pentru listarea lor. • Ele există pe majoritatea sistemelor Unix, dar nu sunt standard sub MS-DOS sau Mac, cu toate că se pot găsi implementări şi pentru aceste sisteme.