Sunteți pe pagina 1din 7

Tehnici de Programare Udriştoiu Ştefan

4. Fişiere Stoica Spahiu Cosmin

Lucrarea 4 – Lucrul cu Fişiere.

Ce este un fişier şi la ce poate folosi el?


Atunci când dorim să memorăm informaţii putem să le păstram în memorie. Singurul
dezavantaj este acela că atunci când închidem programul toate informaţiile se vor pierde.
Alternativa ar fi păstrarea lor pe un suport extern (hard-disk), în fişiere.
Pentru a putea folosi fişiere, avem nevoie să avem posibilitatea să efectuăm câteva
funcţii: citire din fişier, scriere în fişier, regăsire informaţii.
Fiecare fişier care este folosit trebuie deschis în mod explicit înainte ca programul să
poată citi sau scrie în el. Un fişier se deschide folosind funcţia fopen ( ). Ea primeşte ca
parametri numele fişierului (respectiv calea), modalitatea de deschidere, şi va returna un
pointer care va fi folosit în continuare pentru executarea operaţiilor I/O. Acest pointer este de
tipul FILE, care este definită în stdio.h.
Declaraţia variabilei fişier se face astfel:

FILE *fişier;

Deschiderea şi închiderea unui fişier


Funcţia care deschide un fişier este fopen( ). Exemplu:
fisier = fopen („nume.extensie”,”r”);

Variabilei de tipul FILE, fişier i se asociază un pointer către fişierul de deschis cu


numele nume.extensie, pointer returnat de funcţia fopen( ). Fiind un fişier folosit doar de o
anumită aplicaţie, el poate avea orice nume şi extensie doriţi. Nu contează că are extensia .dat
sau .ion ci contează modul de scriere şi citire din el.
„r” semnifică faptul că fişierul este deschis pentru citire. Acest argument se numeşte
mod. În C există mai multe moduri în care un fişier poate fi deschis, în funcţie de scopul
pentru care dorim să îl folosim: citire, scriere, citire şi scriere.
Următorul tabel prezintă modurile în care un fişier poate fi deschis:

Argument Descriere
r Deschide un fişier text pentru citire.
w Creează un fişier text pentru scriere. Dacă acesta există, este suprascris.
Deschide un fişier text în modul adăugare. Textul este adăugat la sfârşitul
a
fişierului.
rb Deschide un fişier binar pentru citire.
wb Creează un fişier binar pentru scriere. Dacă acesta există, este suprascris.
Deschide un fişier binar în modul adăugare. Data este adăugată la sfârşitul
ab
fişierului.
r+ Deschide un fişier text pentru citire şi scriere.

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin

Creează un fişier nou pentru citire şi scriere. Dacă fişierul există, este
w+
suprascris.
a+ Deschide un fişier text pentru citire şi scriere, la sfârşit.
r+b or rb+ Deschide un fişier binar pentru citire şi scriere.
w+b or Creează un fişier binar pentru citire şi scriere. Dacă fişierul există, este
wb+ suprascris.
a+b or ab+ Deschide un fişier binar pentru citire şi scriere, la sfârşit.

Încercarea de a face operaţii cu fişierul în plus faţă de ceea ce ne permite modul în care
acesta a fost deschis, va genera o eroare din partea mediului de programare.
În practică funcţia fopen( ) este de cele mai multe ori inclusă într-un if:

if ((fisier = fopen("nume.extensie", "rb")) == NULL)


fprintf(stderr,"fisierul %s nu poate fi deschis","nume.extensie");

Prin aceasta se verifică dacă fopen a reuşit să deschidă fişierul, în caz contrar
returnând NULL. Pentru a evita eroarea care ar urma să fie generată de program mai departe,
când ar încerca să folosească acel fişier nedeschis, se poate apela funcţia de terminare
program:

if ((fisier = fopen("fisier.extensie", "rb")) == NULL) {


fprintf(stderr,"fisierul %s nu poate fi deschis","nume.extensie");
exit(1);
}

După ce s-a încheiat lucrul cu fişierul, acesta va trebui închis, folosind funcţia close().
De abia după aceea va putea fi eventual redeschis pentru un alt scop (de exemplu era deschis
pentru citire, si se doreşte redeschiderea lui pentru scriere). Funcţia are sintaxa:
fclose (fisier);

După apelul aceste funcţii, nu se mai pot efectua nici un fel de operaţii asupra
fişierului, până la o nouă deschidere.

Citirea din fişier


Citirea dintr-un fişier se execută cu funcţia fread( ). Ea primeşte ca parametri
variabila în care se face citirea, dimensiunea în octeţi cât se citeşte şi pointerul la fişierul din
care se citeşte. Sintaxa este:

fread(&pret,sizeof(pret),1,fisier);
unde: preţ este variabila în care se citeşte şi care poate fi de oricare din tipurile
predefinite sau definite de utilizator din C. Astfel încât nu contează că preţ este de tipul int,
double sau că este o structură definită de utilizator.
Observăm că nu trebuie să specificăm noi neapărat dimensiunea, mai ales că este
posibil să nu o ştim exact. Ea este returnată de funcţia sizeof( ). Fişier reprezintă pointerul
către fişierul de utilizat, descris mai sus.

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin
Atunci când dăm comanda fread( ), se va citi din fişier din poziţia curentă a cursorului
care iniţial, atunci când se deschide fişierul este chiar la început. După prima citire, cursorul
se va afla poziţionat după primii sizeof(pret) octeţi, deci înainte de cea de-a doua înregistrare.
Problema este ce facem atunci când dorim să citim înregistrarea a 3, de exemplu.
Am putea de exemplu să apelăm de 3 ori funcţia fread( ). Acest lucru nu este totuşi
posibil dacă dorim să citim o înregistrare care se află la sfirşîtul fişierului.
O altă variantă este folosirea funcţiei seek( ). Ea are sintaxa:

fseek (fisier, pozitie, origine );

Această funcţie va poziţiona cursorul în fişierul „fisier”, după „pozitie” octeţi,


începând cu poziţia precizată de „origine”. Deci practic va sări peste „poziţie” octeţi
începând din origine.
Originea poate fi: începutul fişierului (origine = SEEK_SET), poziţia curentă a
pointerului în fişier(SEEK_CUR), sau sfârşitul fişierului (SEEK_END).
fseek (fisier, 5*sizeof(pret), SEEK_SET);

Dacă dorim să citim fiecare înregistrare pe rând va trebui să ne poziţionăm la


începutul fişierului (cum?) şi apoi să citim până se ajunge la sfârşit. Funcţia care ne
avertizează că s-a ajuns la sfârşitul fişierului este feof( ). Ea va returna true atunci când s-a
ajuns la sfârşit şi nu se mai poate face nici o citire. Exemplu:

while (! feof (fisier))


fread(&pret, sizeof(pret), 1, fisier);

Scrierea în fişier
Pentru a putea scrie în fişier acesta trebuie în primul rând să fie deschis într-un mod
care permite scrierea. De asemenea trebuie să avem grijă unde scriem, deoarece atunci când
apelăm funcţia de scriere, aceasta va scrie începând cu poziţia curentă, indiferent dacă
suprascrie alte date sau nu.

fwrite(&pret,sizeof(pret),1,fisier);

Parametrii au aceleaşi semnificaţii ca şi la funcţia fread( ).


Dacă dorim să scriem la sfârşitul fişierului, atunci va trebui să ne poziţionăm după
ultima înregistrare (cum?) şi abia apoi să apelăm fwrite( ).
Dacă dorim să înlocuim o anumită înregistrare (de exemplu înregistrarea a 2-a), va
trebui să ne poziţionăm pe ea (cu seek( ) ), iar apoi să dăm comanda de scriere în fişier:
fseek(fisier, sizeof(pret), SEEK_SET);
fwrite(&pret, sizeof(pret), 1, fisier);

Funcţia fseek( ) ne va poziţiona la sizeof(pret) octeţi de începutul fişierului (care


reprezintă de fapt începutul înregistrării nr. 2), iar funcţia fwrite( ) va scrie acolo variabila
pret, peste ce era scris înainte (se va înlocui vechea înregistrare cu cea nouă). Nu se poate
adăuga în mod direct o nouă înregistrare, care să se adauge între 2 deja existente: dacă avem
succesiunea 200 500 600 800 şi dorim să adăugăm 300 între prima şi cea de-a 2-a
înregistrare, prin poziţionarea cursorului înaintea înregistrării 2 şi apelarea funcţiei fwrite( ),
rezultatul va fi 200 300 600 800 şi nu 200 300 500 600 800.

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin

Ştergerea din fişier


În C++ nu există o funcţie care să şteargă efectiv o înregistrare. Şi totuşi …. cum
ştergem dintr-un fişier informaţia care nu mai este necesară?
Există două tipuri de ştergere: ştergere fizică şi ştergere logică.
Ştergerea fizică implică ştergerea efectivă a informaţiei din fişier. (dar parcă
spusesem că nu este posibil?). Pentru aceasta se face următorul artificiu: se va crea un nou
fişier cu un alt nume în care se vor copia toate înregistrările, mai puţin cea care se doreşte să
se şteargă, după care fişierul original va fi şters, iar cel nou creat se va redenumi cu numele
celui şters (folosind funcţia rename ( ) ).

remove(”nume_fisier”);
rename( ”nume_vechi”, ”nume_nou” );

Stergerea logică nu implică nici o ştergere fizică din fişier. De aceea este mult mai
rapidă. Ea implică introducerea unui caracter special în înregistrarea scrisă (respectiv o nouă
variabilă sters de tip boolean care să aibă valoarea true implicit sau false dacă am şters
înregistrarea, pentru cazul în care avem structuri) care să ne semnaleze că înregistrarea
respectivă „este ştearsă” şi va trebui ignorată de acum înainte în toate operaţiile din fişier.
Exemplu: avem variabila pret care are valoarea 500. Atunci când dorim să o
ştergem, îi vom modifica doar valoarea în fişier din 500 în -500 (am adăugat semnul minus).
Prin convenţie, am stabilit că nu există nici un preţ negativ. Prin introducerea semnului
minus, am semnalat că înregistrarea respectivă „am şters-o” şi va trebui ignorată pentru
operaţiile ulterioare de citire şi scriere, deşi ea există în continuare în fişier.
Atenţie:
Dacă avem următoarea secvenţă de înregistrări în fişier: -200 500 600 900 şi dorim
să modificăm valoarea înregistrării 500, în 550, va trebui să ne poziţionăm în fişier după
primii sizeof(preţ) octeţi (adică înainte de înregistrarea numărul 2) şi nu la începutul
fişierului, căci chiar dacă prima înregistrare este ştearsă logic (-200), ea există în fişier.

Exemplu de lucru cu fişiere


Vom gestionăm structuri de date de forma:

typedef struct{
int numar;
int sold;
}cont;

void main(void)
{
char fisier[]="banca.dat";
int tasta;
do{
printf("\ni-iesire "
"c-creare fisier "
"a-adaugare cont "
"d-depunere "
"l- listare "
);

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin
while( !_kbhit() );
tasta=getche();
tasta=tolower(tasta);
printf("\n");
switch(tasta)
{
case 'c':
creare(fisier);
break;
case 'a':
adauga(fisier);
break;
case 'd':
depune(fisier);
break;
case 'l':
listare(fisier);
break;

}
}while(tasta!='i');
}

Utilizatorului i se afişează o listă de opţiuni, fiecărei opţiuni corespunzându-i o tastă


şi i se cere să apese tasta care să-l ducă la opţiunea dorită.
Prima opţiune este creare fişier şi de fapt nu ar trebui să fie lăsată la îndemâna
utilizatorului obişnuit deoarece are ca efect distrugerea vechiului fişier, în caz că acesta
există.

void creare(char* nume)


{
FILE *f;
if((f=fopen(nume,"wb"))!=NULL)
{
fclose(f);
printf("creat cu succes");
}
else
printf("eroare\n");
}

Următoarea operaţiune pe care o implementăm este cea de deschidere cont. Aceasta


are ca efect adăugarea unei noi înregistrări în fişier.

void adauga(char* nume)


{
cont c;
FILE *f;

if((f=fopen(nume,"ab"))!=NULL)
{
printf("numar cont:");
scanf("%d",&c.numar);
getchar();
c.sold=0;
fwrite(&c,sizeof(c),1,f);

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin
fclose(f);
}
else
printf("eroare\n");
}

În continuare o să ne ocupăm de depunere (extragerea se tratează la fel).


void depune(char* nume)
{
cont c,p;
FILE *f;
if((f=fopen(nume,"r+b"))!=NULL)
{
printf("numar cont:");
scanf("%d",&c.numar);
printf("valoare depunere:");
scanf("%d",&c.sold);
while(fread(&p,sizeof(p),1,f)&&
(p.numar !=c.numar));
if(p.numar==c.numar)
{
fseek(f,-(int)sizeof(p),SEEK_CUR);
p.sold+=c.sold;
fwrite(&p,sizeof(p),1,f);
}
else
printf("cont inexistent\n");
fclose(f);
}
else
printf("fisier eroare\n");
}

Pentru a afişa conţinutul fişierului folosim următoarea funcţie:

void listare(char* nume)


{
cont c;
FILE *f;
if((f=fopen(nume,"rb"))!=NULL)
{
while(fread(&c,sizeof(c),1,f))
printf("\ncont:%d sold:%d",c.numar,c.sold);
fclose(f);
}
else
printf("eroare\n");
}

Probleme propuse.
1. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare,
folosind quicksort.

PDF created with pdfFactory Pro trial version www.pdffactory.com


Tehnici de Programare Udriştoiu Ştefan
4. Fişiere Stoica Spahiu Cosmin
2. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare,
folosind sortarea Shell.
3. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare,
folosind sortarea cu fuziuni (MergeSort).
4. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare,
folosind inserţia directă.
5. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare
folosind sortarea prin selecţia maximului.
6. Să se creeze un fişier care să conţină datele dintr-un vector citit de la tastatură, iar
apoi să se sorteze datele scrise în fişier (să se sorteze fişierul), după un câmp oarecare,
folosind sortarea prin selecţia minimului.
7. Să se creeze un fişier care să conţină date despre studenţi. Se foloseşte structură
Student care să conţină nume student, prenume student, notă, materie. Să se sorteze datele
scrise în fişier după nume student. Să se şteargă o anumită înregistrare din fişier.

PDF created with pdfFactory Pro trial version www.pdffactory.com

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