Sunteți pe pagina 1din 39

Programarea calculatoarelor

Limbajul C

CURS 10

Fiiere

Fiier
Colecie de date memorate pe un suport extern (floppy, harddisk, etc) identificat printr-un nume. Entiti ale sistemului de operare: numele lor respect conveniile sistemului, fr legtur cu un limbaj de programare anume Coninutul:
texte (ex. programe surs) numere alte informaii binare: programe executabile, numere n format binar, imagini sau sunete codificate numeric s.a.

Numrul de elemente ale unui fiier este variabil (poate fi nul). Se folosesc pentru
date iniiale sau rezultate mai numeroase pstrarea permanent a unor date de interes pentru anumite aplicaii
Programarea calculatoarelor

Operarea cu fiiere
De obicei "fiier" = fiier disc (pe suport magnetic sau optic) Noiunea de fiier este mai general i include orice flux de date (stream) din exterior spre memorie sau dinspre memoria intern spre exterior. Stream (flux de date, canal) sinonim cu file (fiier): pune accent pe aspectul dinamic al transferului de date Programatorul se refer la un fiier printr-o variabil; tipul acestei variabile depinde de limbajul folosit i chiar de funciile utilizate (n C). Asocierea dintre numele extern (un ir de caractere) i variabila din program se face la deschiderea unui fiier, printr-o funcie standard.
Programarea calculatoarelor

Tipuri de fiiere n C
Fiiere text
conin o succesiune de linii, separate prin NewLine fiecare linie are 0 sau mai multe caractere tipribile i/sau tab

Fiiere binare
conin o succesiune de octei

Programarea calculatoarelor

Fiiere text
Caracter terminator de linie: fiierele Unix/Linux: un singur caracter terminator de linie \n fiierele Windows i MS-DOS: caracterele \r i \n (CR,LF) ca terminator de linie Un fiier text poate fi terminat printr-un caracter terminator de fiier (Ctrl-Z = EOF = -1) nu este obligatoriu acest terminator Sfritul unui fiier disc poate fi detectat i pe baza lungimii fiierului (numr de octei), memorat pe disc. Se realizeaz conversia automat din/n format extern (ir de caractere) n/din format intern (binar virgul fix sau virgul mobil)
Programarea calculatoarelor

Fiiere binare
Pot conine
numere n reprezentare intern (binar) articole (structuri de date) fiiere cu imagini grafice, n diverse formate, etc

Citirea i scrierea se fac fr conversie de format. Pentru fiecare tip de fiier binar este necesar un program care s cunoasc i s interpreteze corect datele din fiier (structura articolelor). Este posibil ca un fiier binar s conin numai caractere, dar funciile de citire i de scriere pentru aceste fiiere nu cunosc noiunea de linie; ele specific un numr de octei care se citesc sau se scriu la un apel al funciei fread sau fwrite.
Programarea calculatoarelor

Operarea cu fiiere
1. se definete o variabil de tip FILE * pentru accesarea fiierului; FILE * un tip structur definit n stdio.h conine informaii referitoare la fiier i la tamponul de transfer de date ntre memoria central i fiier (adresa, lungimea tamponului, modul de utilizare a fiierului, indicator de sfrit, de poziie n fiier) 2. se deschide fiierul pentru un anumit mod de acces, folosind funcia de biblioteca fopen, care realizeaz i asocierea ntre variabila fiier i numele extern al fiierului 3. se prelucreaz fiierul - citire/scriere cu funciile specifice 4. se nchide fiierul folosind funcia de biblioteca fclose.
Programarea calculatoarelor

Deschiderea unui fiier


FILE *fopen(const char *numefiier, const char *mod); Deschide fiierul cu numele dat pentru acces de tip mod Returneaz pointer la fiier sau NULL dac fiierul nu poate fi deschis Valoarea returnat este memorat n variabila fiier, care a fost declarat (FILE *) pentru accesarea lui. numefis: numele fiierului mod: ir de caractere (ntre 1 i 3 caractere):
"r" - readonly , este permis doar citirea dintr-un fiier existent "w" - write, creaz un nou fiier, sau dac exist deja, distruge vechiul coninut "a" - append, deschide pentru scriere un fiier existent (scrierea se va face n continuarea informaiei deja existente n fiier, deci pointerul de acces se plaseaz la sfritul fiierului) + = permite scrierea i citirea din acelasi fiier - actualizare (ex: "r+", "w+", "a+"). "t" sau "b" = tip fiier ("text", "binary"), implicit este "t
Programarea calculatoarelor

Nume extern fiier


Poate include urmtoarele:
Numele unitii de disc sau partiiei disc ( ex: A:, C:, D:, E:) "Calea" spre fiier: succesiune de nume de fiiere catalog (director), separate printr-un caracter ('\' n MS-DOS i MSWindows, sau '/' n Unix i Linux) Numele propriu-zis al fiierului Extensia, care indic tipul fiierului i care poate avea ntre 0 i 3 caractere n MS-DOS.

Sistemele MS-DOS i MS-Windows nu fac deosebire ntre litere mari i litere mici, n cadrul numelor de fiiere Atenie! pentru separarea numelor de cataloage dintr-o cale se vor folosi:
"\\", pentru a nu se considera o secven de caractere "Escape" sau caracterul /. char *numef = "C:\\WORK\\T.TXT"; char *numef = c:/work/t.txt;
Programarea calculatoarelor

nchiderea unui fiier


int fclose(FILE *fp);
nchide fiierul i elibereaz zona tampon n caz de succes ntoarce 0. altfel, ntoarce EOF.

Atenie!
nchiderea unui fiier disc este absolut necesar pentru fiierele n care s-a scris ceva! Poate lipsi dac s-au fcut doar citiri din fiier!
Programarea calculatoarelor

Exemplu
#include <stdio.h> int main ( ) { FILE * f; // pentru referire la fiier // deschide un fiier text ptr citire f = fopen ( c:\\t.txt", "rt ); printf ( f == NULL ? "Fiier negasit" : " Fiier gasit"); if (f) // dac fiier existent fclose(f); // nchide fiier return 0; }
Programarea calculatoarelor

Prelucrarea fiierelor text


se poate face fie la nivel de linie, fie la nivel de caracter:
int fgetc (FILE *fp) ntoarce urmtorul caracter din fp ca un unsigned char convertit la int, sau EOF dac s-a ntlnit sfritul de fiier sau n caz de eroare. char *fgets (char *s, int n, FILE *fp) citete maxim n-1 caractere sau pn la '\n' inclusiv, i le depune n s, adaug la sfrit '\0' i returneaz adresa irului. La eroare ntoarce valoarea NULL. int fputc(int c,FILE *fp) scrie caracterul cu codul ascii c n fiier char *fputs(char *s,FILE *fp) scrie irul n fiier, fara caracterul '\0'. La eroare ntoarce EOF.
Programarea calculatoarelor

Exemplu: citire i afiare linii dintr-un fiier


#include<stdio.h> #include<stdlib.h> int main() { FILE *fp; char s[80]; if ( (fp=fopen("c:\\test.c","r")) == NULL ) { printf ( "Nu se poate deschide la citire fiierul!\n ); exit (1); } while ( fgets(s,80,fp) != NULL ) printf ( "%s", s); fclose (fp); return 0; }
Programarea calculatoarelor

Exemplu: scriere sub form de litere mici caracterele dintr-un fiier n alt fiier
#include<stdio.h> #include<ctype.h> #include<stdlib.h> int main () { FILE * f1, * f2; int ch; f1= fopen ("c:\\1cc\\in.txt", "r"); f2= fopen ("c:\\1cc\\out.txt", "w"); if ( f1==0 || f2==0) { puts (" Eroare la deschidere fiiere \n"); system("pause"); return 1; } while ( (ch=fgetc(f1)) != EOF) // citeste din f1 fputc ( tolower(ch),f2); // scrie n f2 fclose(f1); fclose(f2); system("pause"); return 0; }
Programarea calculatoarelor

Intrri/ieiri cu conversie de format


Datele numerice pot fi scrise n fiiere disc n format intern, binar (mai compact) transformate n iruri de caractere (cifre zecimale, semn .a): fiier text ocup mai mult spaiu Formatul ir de caractere necesit i caractere separator ntre numere, dar poate fi citit cu programe scrise n orice limbaj sau cu orice editor de texte sau cu alt program utilitar de vizualizare fiiere! int fprintf (FILE *fp, const char *format,...) identic cu printf cu deosebirea c scrie ntr-un fiier. int fscanf (FILE *fp, const char *format,...) realizeaz citirea cu format dintr-un fiier; analog scanf Exemplu: fscanf ( fp, %d%f ,&a, &b); fprintf ( fp, a= %d \t b=%f \n, a, b);
Programarea calculatoarelor

Testare sfrit de fiier


int feof(FILE *fp) testeaz dac s-a ajuns la end-of-file al fiierului referit de fp returneaz 0 dac nu s-a detectat sfrit de fiier la ultima operaie de citire, respectiv o valoare nenul (adevarat) pentru sfrit de fiier. Atenie! Se va scrie n fiierul de ieire i 1 - rezultatul ultimului apel al funciei fgetc: while ( ! feof(f1)) fputc(fgetc(f1),f2); Soluia preferabil pentru ciclul de citire-scriere caractere este testarea rezultatului funciei de citire: while ( (ch=fgetc(f1)) != EOF) fputc ( ch, f2);

Programarea calculatoarelor

Exemplu
ntr-un fiier de tip text sunt pstrate valorile reale ale unei msuratori sub forma: nr_msuratori '\n' val1 '\n' val2 '\n' val3 ... S se scrie programul care afieaz numrul de msurtori i valorile respective, dup care adaug la fiier noi msuratori pn la introducerea valorii 0. Valorile citite se afieaza n format tiinific.

Programarea calculatoarelor

Rezolvare
# include <math.h> # include <stdio.h> # include <stdlib.h> # include <ctype.h> # define MAX 100 double convf (char *s) { double val=0.0, putere; int i=0,semn; while ( isspace(s[i]) ) i++; semn = (s[i]=='-')?-1:1; if (s[i]=='+ || s[i]=='- ) i++; for ( val=0.0; isdigit(s[i]); i++) val = 10*val + s[i]-'0;
Programarea calculatoarelor

Rezolvare
if (s[i]=='.') { i++; for (putere=1.0; isdigit(s[i]); i++) { val = 10*val + s[i]-'0'; putere *= 10; } val /= putere; } /*sfirsit parte zecimala*/ val *= semn; return val; } void loadmat (FILE *fp, int *nrm, double *mas){ int i=0; fscanf (fp,"%d", nrm); if (*nrm>MAX) *nrm = MAX; for ( ; i<*nrm; i++) fscanf (fp, "%lf", &mas[i]); }
Programarea calculatoarelor

Rezolvare
void afiseaza(double *mas,int nrm){ int i; for (i=0; i<nrm; i++) printf ("Masuratoarea %d = %6.2e\n", i+1, mas[i]); } int main(){ FILE *fp; double masur[MAX], mas_noua; char nume_fis[12], s[20]; int nr_mas; printf ("nume fisier:"); gets (nume_fis); if ( (fp = fopen(nume_fis, "r+") ) == 0 ){ printf ("nu exista fisierul\n"); exit (1); }
Programarea calculatoarelor

Rezolvare
loadmat (fp,&nr_mas,masur); afiseaza (masur,nr_mas); fseek (fp, 0L, SEEK_END); // pozitionare la sfarsit printf ("\nmasuratoarea %d =",++nr_mas); while ( (mas_noua=convf(gets(s))) && nr_mas<MAX-1){ printf ("\nmasuratoarea %d =", ++nr_mas); fprintf (fp, "%lf\n", mas_noua); } fseek (fp, 0L, SEEK_SET); // pozitionare la inceput fprintf (fp, "%d", --nr_mas); fclose (fp); system ("pause"); return 0; }
Programarea calculatoarelor

Exerciii
Program pentru numrarea liniilor i cuvintelor dintrun fiier text. Cuvintele sunt iruri de orice caractere separate ntre ele prin (oricte) spaii albe. Se va folosi funcia de biblioteca "strtok". Exemplu strtok: char *p, *sep= ="\t \r\n" ; while ( (p= strtok (p,sep)) != NULL) { p=p+strlen(p)+1; }
Programarea calculatoarelor

Funcii de acces la fiiere binare


Un fiier binar este format n general din articole de lungime fix, fr separatori ntre articole. Un articol poate conine
un singur octet un numr binar (pe 2,4 sau 8 octei) o structur cu date de diferite tipuri.

Funciile de acces pentru fiiere binare "fread" i "fwrite" pot citi sau scrie unul sau mai multe articole, la fiecare apelare. Transferul ntre memorie i suportul extern se face fr conversie sau editare (adugare de caractere la scriere sau eliminare de caractere la citire).
Programarea calculatoarelor

Funcii intrare/iesire (fiiere binare b)


size_t fread (void *ptr, size_t size, size_t nmemb, FILE *fp) citete la adresa ptr cel mult nmemb elemente de dimensiune size din fiierul referit de fp: int a[10]; fread (a, sizeof(int), 10, fp); size_t fwrite (void *ptr, size_t size, size_t nmemb, FILE *fp) scrie n fiierul referit de fp cel mult nmemb elemente de dimensiune size de la adresa ptr: fwrite(a, sizeof(int),10,fp); Rezultatul funciilor "fread" i "fwrite" este numrul de articole efectiv citite sau scrise Este diferit de argumentul 3 numai la sfrsit de fiier (la citire) sau n caz de eroare de citire/scriere.

Programarea calculatoarelor

assert
void assert (int expr); Permite ca informaii de diagnostic s fie scrise la fiierul standard de eroare. Dac expr este 0 (fals), atunci expresia expr, numele fiierului i linia n care a aprut sunt trimise la fiierul standard de eroare dup care execuia programului este oprit: Assertion failed: expr, file filename, line line-number Exemplu:
#include<assert.h> void open_record(char *record_name) { assert ( record_name != NULL ); /* Rest of code */ } int main(void) { open_record(NULL); }
Programarea calculatoarelor

Exemplu: operaii cu un fiier de elevi (nume i medie)


#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> typedef struct { char nume[25]; float medie; } Elev; // creare fiier cu nume dat void creare(char * numef) { FILE * f; Elev s; f=fopen(numef,"wb"); assert (f != NULL); printf ("Nume i medie ptr. fiecare student :\n"); while ( scanf ("%s%f", s.nume, &s.medie) != EOF) fwrite (&s, sizeof(s), 1, f); fclose (f); }
Programarea calculatoarelor

Exemplu
// afisare coninut fiier pe ecran void listare (char* numef) { FILE * f; Elev e; f = fopen (numef, "rb"); assert (f != NULL); printf ("Nume i medie: \n"); while ( fread (&e, sizeof(e), 1, f ) ==1 ) printf ("%-25s %6.2f \n", e.nume, e.medie); fclose (f); } // adaugare articole la sfritul unui fiier existent void adaugare (char * numef) { FILE * f; Elev e; f = fopen (numef, "ab"); assert (f != NULL); printf ("Adaugare nume i medie:\n"); while (scanf ("%s%f", e.nume, &e.medie) != EOF) fwrite (&e, sizeof(e), 1, f); fclose (f); }
Programarea calculatoarelor

Acces direct la datele dintr-un fiier


posibilitatea de a citi sau scrie oriunde ntr-un fiier, printr-o poziionare prealabil nainte de citire sau scriere n C poziionarea se face pe un anumit octet din fiier, iar funciile standard permit accesul direct la o anumit adres de octet din fiier. Funciile pentru acces direct din <stdio.h> permit operaiile urmtoare: Pozitionarea pe un anumit octet din fiier ("fseek"). Citirea poziiei curente din fiier ("ftell"). Memorarea poziiei curente i poziionare ("fgetpos", "fsetpos"). Poziia curent n fiier este un numr de tip long, pentru a permite operaii cu fiiere foarte lungi!

Programarea calculatoarelor

Funcii pentru acces direct


long int ftell (FILE *fp) ntoarce valoarea indicatorului de poziie Pentru fiier binar: numrul de octei de la nceputul fiierului Fiier text: o valoare ce poate fi utilizat de fseek pentru a seta indicatorul de poziie n fiier la aceast poziie. int fseek (FILE *fp, long int offset, int poziie) poziioneaz indicatorul de poziie la valoarea dat de offset fa de poziie: SEEK_SET = 0 - Cutarea se face de la nceputul fiierului SEEK_CUR = 1 - Cutare din poziia curent SEEK_END = 2 - Cutare de la sfritul fiierului Intr-un fiier text poziionarea este posibil numai fat de nceputul fiierului, iar poziia se obine printr-un apel al funciei ftell!
Programarea calculatoarelor

Exemple
poziionarea la sfritul fiierului: fseek (fp, 0, SEEK_END) poziionarea la caracterul precedent: fseek (fp, -1, SEEK_CUR) poziionarea la inceputul fiierului: fseek (fp, 0, SEEK_SET)
Atenie! Poziionarea relativ la sfritul unui fiier nu este garantat nici chiar pentru fiiere binare, astfel c ar trebui evitat! Ar trebui evitat i poziionarea fa de poziia curent cu o valoare negativ, care nu funcioneaz n toate implementrile!

Programarea calculatoarelor

Funcii pentru acces direct


int fgetpos (FILE *fp, fpos_t *poziie) memoreaz starea curent a indicatorului de poziie al fluxului referit de fp n poziie; ntoarce 0 dac operaia s-a realizat cu succes! int fsetpos (FILE *fp, const fpos_t *poziie) seteaz indicatorul de poziie al fluxului referit de fp la valoarea data de poziie void rewind (FILE *fp) seteaz indicatorul de poziie al fluxului referit de fp la nceputul fiierului
Programarea calculatoarelor

Funcie care modific coninutul mai multor articole din fiierul de elevi creat anterior
// modificare coninut articole, dupa cautarea lor void modificare (char * numef) { FILE * f; Elev e; char nume[25]; long pos; int ef; f = fopen(numef,"rb+"); assert (f != NULL); do { printf ("Nume cautat: "); scanf ("%s",nume); if (strcmp(nume, .) == 0) break; // datele se termin cu un punct // cauta "nume" n fiier fseek (f, 0, 0); // readucere pe inceput de fiier while ( (ef=fread (&e, sizeof(e), 1, f)) ==1 ) if (strcmp (e.nume, nume)==0) { pos= ftell(f) - sizeof(e); break; }

Programarea calculatoarelor

Exemplu
if ( ef < 1) break; printf ("noua medie: "); scanf ("%f", &e.medie); fseek (f, pos, 0); // pe inceput de articol gasit fwrite (&e, sizeof(e), 1, f); // rescrie articol modificat } while (1); fclose (f); } int main(){ char name[]="c:elev.txt; creare (name); listare (name); adaugare (name); modificare (name); listare (name); system("pause"); return 0; }

Programarea calculatoarelor

Fiiere predefinite
Exist trei fluxuri predefinite, care se deschid automat la lansarea unui program: stdin - fiier de intrare, text, este intrarea standard - tastatura stdout - fiier de ieire, text, este ieirea standard - ecranul monitorului. stderr - fiier de iesire, text, este ieirea standard de erori - ecranul monitorului. pot fi folosite n diferite funcii practic se folosesc n funcia "fflush" care golete zona tampon ("buffer") asociat unui fiier.
Programarea calculatoarelor

Redirectarea fiierelor standard


Prin redirectare, fiierele standard se pot asocia cu alte fiiere. Exemplu: fiier_exe <fiier_1 >fiier_2 n acest caz, preluarea informaiilor se face din fiier_1, iar afiarea informaiilor de ieire se face n fiier_2.

Programarea calculatoarelor

Observaii
Nu orice apel al unei funcii de citire sau de scriere are ca efect imediat un transfer de date ntre exterior i variabilele din program! Citirea efectiv de pe suportul extern se face ntr-o zon tampon asociat fiierului, iar numrul de octei care se citesc depind de suport: o linie de la tastatur, unul sau cteva sectoare disc dintr-un fiier disc, etc. Cele mai multe apeluri de funcii de I/E au ca efect un transfer ntre zona tampon (anonim) i variabilele din program. Funcia fflush are rolul de a goli zona tampon folosit de funciile de I/E, zon altfel inaccesibil programatorului C. Are ca argument variabila pointer asociat unui fiier la deschidere, sau variabilele predefinite stdin i stdout.
Programarea calculatoarelor

Exemple de situaii n care este necesar folosirea funciei fflush:


Citirea unui caracter dup citirea unui cmp sau unei linii cu scanf : int main () { int n; char s[30]; char c; scanf (%d,&n); // sau scanf(%s,s); // fflush(stdin); // pentru corectare c= getchar(); // sau scanf (%c, &c); printf (%d \n,c); // afiseaza codul lui c return 0; } va afia 10 care este codul numeric al caracterului terminator de linie \n, n loc s afieze codul caracterului c! dup o citire cu scanf n zona tampon rmn unul sau cteva caractere separator de cmpuri (\n,\t, ), care trebuie scoase de acolo prin fflush(stdin) sau prin alte apeluri scanf.
Programarea calculatoarelor

Exemple de situaii n care este necesar folosirea funciei fflush:


Funcia scanf oprete citirea unei valori din zona tampon ce conine o linie la primul caracter separator de cmpuri sau la un caracter ilegal n cmp (de ex. liter ntr-un cmp numeric)! In cazul repetrii unei operatii de citire (cu scanf) dup o eroare de introducere n linia anterioar (caracter ilegal pentru un anumit format de citire) n zona tampon rmn caracterele din linie care urmau dup cel care a produs eroarea! do { printf ("x, y= "); err = scanf ("%d%d", &x, &y); if ( err == 2 ) break; fflush (stdin); } while (err != 2); Dup citirea unei linii cu funciile gets sau fgets nu rmne nici un caracter n zona tampon i nu este necesar apelul lui fflush!
Programarea calculatoarelor

Exemple de situaii n care este necesar folosirea funciei fflush:


Se va folosi periodic fflush n cazul actualizrii unui fiier mare, pentru a evita pierderi de date la producerea unor incidente (toate datele din zona tampon vor fi scrise efectiv pe disc):
int main () { FILE * f; int c ; char numef[]="TEST.DAT"; char x[ ] = "0123456789"; f=fopen (numef,"w"); for (c=0;c<10;c++) fputc (x[c], f); fflush (f); // sau fclose(f); f=fopen (numef,"r"); while ( (c=fgetc(f)) != EOF) printf ("%c", c); return 0; }
Este posibil ca s existe diferene n detaliile de lucru ale funciilor standard de citire-scriere din diferite implementri (biblioteci), deoarece standardul C nu precizeaz toate aceste detalii!
Programarea calculatoarelor

S-ar putea să vă placă și