Fisiere Structuri de Date

13

Click here to load reader

description

Fisiere Structuri de Date

Transcript of Fisiere Structuri de Date

Page 1: Fisiere Structuri de Date

Noţiunea de acces trebuie aplicată atât pentru operaţia de scriere, cît şi pentru cea de citire a datelor.

Poziţia din/în care se face citirea/scrierea în cadrul fişierului este indicatăde un pointer. Accesul la datele înregistrate pe un purtător tehnic poate fi secvenţialsau direct, în funcţie de modul în care se stabileşte pointerul.

Accesul secvenţial este posibil la toţi purtătorii tehnici de date şi presupune înscrierea înregistrărilor în ordinea furnizării lor sau regăsirea în ordinea în care au fost înscrise în support.

Pointerul de fişier avansează, în scriere şi citire, de la o entitate (articol, bloc, linie sau câmp) la alta. Dacă pointerul se exprimă prin deplasare faţă prin deplasare, în octeţi, faţă de începutul fişierului (la unele sisteme numărul relativ este stabilit de la unu: P*(Ak)=k).

La scriere, articolul Ak (numărul relativ k-1) se memorează pe poziţia sa, celelalte k-1 articole anterioare putând să nu existe (pe suport există însă rezervat loc pentru ele). La citire, articolul Ak (cu numărul relativ k-1, kn) este localizat direct şi conţinutul lui se transferă în memoria internă.

Fişierele organizate secvenţial, cu articole de lungime variabilă, admit numai accesul secvenţial. Fişierele organizate secvenţial, cu articole sau blocuri de lungime fixă, admit atât accesul secvenţial, cât şi pe cel relativ. Acest lucru derivă din faptul că accesul relativ este realizat de sistem printr-o deplasare secvenţială faţă de începutul acestuia, deplasare care este egală cu valoarea expresiei:

număr_relativ × lungime_articol.Asupra unui fişier se pot executa diverse operaţii de prelucrare, numite şi

de gestiune, care se împart în operaţii la nivel de fişier şi la nivel de articol.Operaţiile la nivel de fişier se referă la aspecte ca: înscrierea fişierului în

[sub]directoare, validarea şi interzicerea accesului la fişier (deschidere/închidere), ştergerea fişierului din [sub]directoare (ştergere) etc. Aceste operaţii se regăsesc, întotalitate, la prelucrarea fişierelor pe discuri magnetice. În cazul purtătorilor nereutilizabili, singurele operaţii care au sens sunt cele de deschidere/închidere a fişierelor.

Operaţiile la nivel de articol se referă la accesul la entităţile de date alefişierului (articole, blocuri, linii sau câmpuri) în vederea prelucrării lor. Privite subaspectul semnificaţiei pentru utilizator, aceste operaţii se referă la: înscriereainiţială a entităţilor pe purtătorul tehnic (populare), actualizarea fişierului prinincluderea de noi entităţi (adăugare), modificarea valorilor unor câmpuri din anumite entităţi (modificare), eliminarea entităţilor care nu mai sunt necesare (ştergere), regăsirea entităţilor în vederea satisfacerii unor cerinţe de informare (consultare). În programele C, operaţiile de I/E sunt realizate cu ajutorul unei mulţimi de funcţii specializate pentru căutare, scriere, citire etc.

În concluzie, dacă din punctul de vedere al utilizatorului operaţiile de prelucrare se descriu relativ simplu, prin apeluri de funcţii, realizarea efectivă a lorde către sistemul de calcul este complexă. În sistemul de operare MS-DOS sunt incluse funcţii de întrerupere care, prin intermediul BIOS (Basic Input Output System), lansează anumite operaţii cu un echipament.

Din punct de vedere al reprezentării datelor în suportul extern, se disting fişiere text, în care toate datele sunt sub formă ASCII (un caracter/octet) şi fişiere binare, în care toate datele sunt memorate în forma identică cu cea din memoria principală (MP).

Strâns legat de lucrul cu cele două tipuri de fişiere este modul în care se face transferul datelor între memoria principală şi suportul extern: transfer posibil cu conversie (în cazul fişierelor text) şi transfer fără conversie (în cazul fişierelor binare).

Page 2: Fisiere Structuri de Date

Indiferent de limbajul de programare folosit, operaţiile necesare pentru prelucrarea fişierelor sunt:• descrierea fişierului (crearea tabelei care memorează caracteristicile fişierului);• asignarea fişierului intern (numele logic) la unul extern (fizic);• deschiderea fişierului;• operaţii de acces la date („articole”);• închiderea fişierului.

Pentru lucrul cu fişiere trebuie identificate tipurile acestora, metodele de organizare, modurile de acces şi tipurile de articole acceptate. Din punct de vedere al tipurilor de date, în C există un singur tip de fişiere: flux de octeţi (înşiruire de octeţi, fără niciun fel de organizare sau semnificaţie). Organizarea acestui flux de octeţi este secvenţială. Accesul la fişiere se poate face secvenţial sau direct (cu excepţia fişierelor standard, la care accesul este numai secvenţial). În bibliotecile limbajului există funcţii predefinite pentru prelucrarea fişierelor. Funcţiile de prelucrare la nivel superior a fişierelor tratează fluxul de octeţi acordându-i o semnificaţie oarecare. Putem spune că din punct de vedere al prelucrării, la acest nivel, ne putem referi la fişiere text şi fişiere binare.

Mod Scop

aDeschide un fişier existent pentru adăugare la sfîrşit (extindere) sau îl creează dacă nu există. Este permisă numai scrierea. Numai pentru fişiere text.

r Deschide un fişier existent numai pentru citire

wSuprascrie un fişier existent sau creează unul nou, permiţîndu-se numai operaţia de scriere

a+Deschide un fişier existent pentru adăugare la sfîrşit (extindere) sau îl creează dacă nu există. Sînt permise citiri şi scrieri. Numai pentru fişiere text.

r+ Deschide un fişier existent pentru citire şi scriere

w+Suprascrie un fişier existent sau creează unul nou, permiţîndu-se atît citiri cît şi scrieri.

La opţiunile de mai sus se poate adăuga b pentru fişiere binare sau t pentru fişiere text.

Dacă nu este prezentă nici litera b nici litera t, modul considerat depinde de valoarea variabilei _fmode : dacă valoarea este O_BINARY, se consideră fişier binar; dacă valoarea este O_TEXT, se consideră fişier text. De obicei implicită este valoarea O_TEXT.

Modurile uzuale pentru deschiderea fişierelor sînt prezentate în tabelul 2.

Page 3: Fisiere Structuri de Date

Tabelul 2. Moduri uzuale pentru deschiderea fişierelor

Operaţia de gestiune Fişiere text Fişiere binare

Creare w wb

Consultare r rb

Actualizare r+b

Creare şi actualizare w+ rwb, w+b

Extindere a

Închiderea fişierelor se realizează prin apelul funcţiei fclose, care are următorul prototip:

int fclose(FILE* f);

Funcţia închide fişierul primit ca parametru.

Returnează valoarea 0 în caz de succes sau -1, în caz de eroare.

Înainte de închiderea fişierului, sînt golite toate zonele tampon asociate lui. Zonele tampon alocate automat de sistem sînt eliberate.

Revenirea la începutul fişierului se realizează prin funcţia rewind, cu prototipul:

void rewind(FILE *f);

Efect: poziţionarea la începutul fişierului f (care era deschis anterior), resetarea indicatorului de sfîrşit de fişier şi a indicatorilor de eroare (se înscrie valoarea 0). După apelul lui rewind poate urma o operaţie de scriere sau citire din fişier.

Testarea sfîrşitului de fişier, se realizează prin apelul macrodefiniţiei feof:

int feof(FILE* f);

Macro-ul furnizează valoarea indicatorului de sfîrşit de fişier asociat lui f. Valoarea acestui indicator este setată la fiecare operaţie de citire din fişierul respectiv. Valoarea întoarsă este 0 (fals) dacă indicatorul are

Page 4: Fisiere Structuri de Date

valoarea sfîrşit de fişier şi diferit de zero (adevărat) în caz contrar. Apelul lui feof trebuie să fie precedat de apelul unei funcţii de citire din fişier. După atingerea sfîrşitului de fişier, toate încercările de citire vor eşua, pînă la apelul funcţiei rewind sau închiderea şi redeschiderea fişierului .

Golirea explicită a zonei tampon a unui fişier se realizează prin apelul funcţiei fflush, care are următorul prototip:

int fflush(FILE* f);

Dacă fişierul f are asociată o zonă tampon de ieşire, funcţia scrie în fişier toate informaţiile din acesta, la poziţia curentă. Dacă fişierul are asociată o zonă tampon de intrare, funcţia îl goleşte. În caz de succes returnează valoarea zero, iar în caz de eroare valoarea EOF (definită în stdio.h).

Exemplu: înainte de a citi un şir de caractere de la tastatură, zona tampon trebuie golită pentru a preveni citirea unui şir vid (datorită unei perechi CR/LF rămase în zona tampon de la o citire anterioară a unei valori numerice). Ştergerea se realizează prin apelul:

fflush(stdin);

Aflarea poziţiei curente în fişier se realizează prin apelul uneia din funcţiile fgetpos sau ftell:

int fgetpos(FILE* f,fpos_t* poziţie);

După apel, la adresa poziţie se află poziţia pointerului de citire/scriere din fişierul f, ca număr relativ al octetului curent. Primul octet are numărul 0. Valoarea returnată poate fi folosită pentru poziţionare cu funcţia fsetpos. În caz de succes funcţia întoarce valoarea 0, iar în caz de eroare o valoare nenulă şi setează variabila errno la valoarea EBADF sau EINVAL.

long ftell(FILE* f);

returnează poziţia în fişierul f a pointerului de citire/scriere în caz de succes sau -1L în caz contrar. Dacă fişierul este binar, poziţia este dată în număr de octeţi faţă de începutul fişierului. Valoarea poate fi folosită pentru poziţionare cu funcţia fseek.

Modificarea poziţiei pointerului de citire/scriere se poate face prin poziţionare relativă:

int fseek(FILE* f,long deplasare,int origine);

unde deplasare reprezintă numărul de octeţi cu care se deplasează pointerul în fişierul f, iar origine reprezintă poziţia faţă de care se deplasează pointerul. Parametrul origine poate fi: SEEK_SET (0) – poziţionare faţă de începutul fişierului; SEEK_CUR (1) – poziţionare faţă de poziţia curentă; SEEK_END (2) – poziţionare faţă de sfîrşitul fişierului. Funcţia returnează valoarea 0 în caz de succes (şi uneori şi în caz de eşec). Se semnalează eroare prin returnarea unei valori nenule numai în cazul în care f nu este deschis.

Page 5: Fisiere Structuri de Date

Poziţionarea absolută se face cu funcţia:

int fsetpos(FILE* f,const fpos_t poziţie);

Pointerul de citire/scriere se mută în fişierul f la octetul cu numărul indicat de parametrul poziţie (care poate fi o valoare obţinută prin apelul lui fgetpos).

Ambele funcţii resetează indicatorul de sfîrşit de fişier şi anulează efectele unor eventuale apeluri anterioare ale lui ungetc asupra acelui fişier.

Redenumirea sau mutarea unui fişier existent se poate realiza prin apelul funcţiei rename, care are următorul prototip:

int rename(const char* n_vechi,const char* n_nou);

unde n_vechi reprezintă vechiul nume al fişierului, iar n_nou reprezintă numele nou.

Dacă numele vechi conţine numele discului (de exemplu C:), numele nou trebuie să conţină acelaşi nume de disc. Dacă numele vechi conţine o cale, numele nou nu este obligat să conţină aceeaşi cale. Folosind o altă cale se obţine mutarea fişierului pe disc. Folosind aceeaşi cale (sau nefolosind calea) se obţine redenumirea fişierului. Nu sînt permise wildcard-uri (?, *) în cele două nume.

În caz de succes se întoarce valoarea 0. În caz de eroare se întoarce -1 şi errno primeşte una din valorile: ENOENT – nu există fişierul, EACCES – nu există permisiunea pentru operaţie sau ENOTSAM – dispozitiv diferit (mutarea se poate face doar pe acelaşi dispozitiv).

Ştergerea unui fişier existent se poate realiza prin apelul funcţiei unlink, prezentată anterior, sau remove, care are următorul prototip:

int remove(const char* cale);unde cale reprezintă specificatorul fişierului (trebuie să fie închis).

Citirea dintr-un fişier binar se realizează prin apelul funcţiei fread, care are următorul prototip:

size_t fread(void* ptr,size_t dim,size_t n,FILE* f);

Funcţia citeşte din fişierul f, de la poziţia curentă, un număr de n entităţi, fiecare de dimensiune dim, şi le depune, în ordinea citirii, la adresa ptr. fread returnează numărul de entităţi citite. În total se citesc, în caz de succes, n*dim octeţi. În caz de eroare sau cînd se întîlneşte sfîrşitul de fişier, funcţia returnează o valoare negativă sau 0; size_t este definit în mai multe header-e (între care stdio.h) şi este un tip de dată folosit pentru a exprima dimensiunea obiectelor din memorie. Este compatibil cu tipul unsigned.

Exemplu:

Page 6: Fisiere Structuri de Date

struct complex {int x,y} articol; FILE * f_complex;if(f_complex=fopen("NR_COMPL.DAT", "rb") fread(&articol,sizeof(articol),1,f_complex);else printf("Fisierul nu poate fi deschis");

În exemplul anterior se deschide un fişier binar din care se citeşte un articol de tip struct complex care se depune în variabila articol.

Scrierea într-un fişier binar se poate realiza prin apelul funcţiei fwrite, care are următorul prototip:

size_t fwrite(const void* ptr,size_t dim,size_t n,FILE* f);

Funcţia scrie în fişierul f, începînd cu poziţia curentă, un număr de n entităţi contigue, fiecare de dimensiune dim, aflate în memorie la adresa ptr; fwrite returnează numărul entităţilor scrise cu succes. În caz de eroare se returnează o valoare negativă.

Exemplu:

struct complex {int x,y} articol;FILE *pf;pf=fopen("NR_COMPL.DAT","wb");fwrite(& articol,sizeof (articol),1,pf);

Exemplul anterior creează un fişier binar nou în care scrie o secvenţă de octeţi conţinînd reprezentarea binară a unei date de tip struct complex.

Fişiere text.Lucrul cu fişiere text în limbajul C presupune parcurgerea urmă toarelor etape:1. Deschiderea fişierului2. Prelucră ri asupra fişierului (citiri, scrieri)3. Închiderea fişierului

1. Deschiderea unui fişier se realizează cu funcţia fopen. În continuare este prezentat prototipul funcţiei fopen:FILE *fopen(char *nume_fis,char *mod), unde nume_fis este un şir de caracterecare conţine numele fişierului iar mod este un şir de caractere care va precizaoperaţiile ce vor fi efectuate asupra fişierului precum şi tipul de fişier.Dacă operaţia de deschidere a fişierului a decurs corect, pointerul întors de fopen este diferit de NULL. Dacă , din diverse motive, deschiderea nu s-a putut efectua corect, fopen va întoarce NULL, fapt ce trebuie testat înainte de a trece la alte prelucrări.Ex:FILE *fis_in;

Page 7: Fisiere Structuri de Date

fis_in=fopen(“in.txt”,”rt”);if(fis_in==NULL){printf(“Eroare la deschiderea fisierului – in.txt— “);getch();}2 Prelucră ri asupra fişierului. Operaţii de citire, scriere.a) Citirea din fişiera1) Citirea unui caracter. Aceasta se realizează utilizâ nd funcţia fgetc.Prototipul: int fgetc(FILE *f)Ex:char c;FILE *fis_in;//… … …c=fgetc(fis_in);//… … …Ex: Afişarea conţinutului unui fişier text#include<stdio.h>#include<conio.h>void main(void){FILE *fin;char c;clrscr();fin=fopen("in.txt","rt"); //deschiderea fisierului, pentru citireif(fin==NULL) //se testeaza daca deschiderea fisierului s-a efectuat cu succes{printf("Eroare la deschiderea fisierului in.txt");getch();return;}while((c=fgetc(fin))!=EOF) //citirea din fisierputc(c,stdout); //afisarea caracterului citit din fisierfclose(fin); //inchiderea fisieruluigetch();}a2) Citirea unui şir de caractere. Aceasta se realizează utilizâ nd funcţia fgets.Prototipul: char* fgets(char *s, int n, FILE *f)Ex:char sir[50];FILE *fis_in;//… … … .fgets(sir,50,fis_in); //citirea in tabloul s a maxim 50 caractere//… … … .a3) Funcţia fscanf. Această funcţie este similară funcţiei scanf, cu precizarea cădatele nu sunt citite de la tastatură , ci dintr-un fişier. Funcţia fscanf returnează

Page 8: Fisiere Structuri de Date

numă rul de valori citite din fişier.Prototipul: int fscanf(FILE *f, char *format, … )Dacă primul argument al funcţiei este stdin atunci datele vor fi citite din fişierulstandard de intrare (tastatura).Ex:int n,m;FILE *fis_in;//… … …fscanf(fis_in,”%d%d”,&n,&m);//… … … .b) Scrierea în fişierb1) Scrierea unui caracter într-un fişier. Aceasta se realizează utilizâ nd funcţiafputc.Prototipul: int fputc(int c, FILE *f);Ex:char c;c=’a’;FILE *fis_out;//… … … .fputc(c,fis_out);//… … … .Ex: Copierea conţinutului unui fişier de intrare într-un fişier de ieşire.#include<stdio.h>#include<conio.h>void main(void){FILE *fin,*fout;char c;clrscr();fin=fopen("in.txt","rt"); //deschiderea fisierului de intrare, pentru citireif(fin==NULL) //se testeaza daca deschiderea fisierului s-a efectuat cu succes{printf("Eroare la deschiderea fisierului in.txt");getch();return;}fout=fopen("out.txt","wt"); //deschiderea fisierului de iesire, pentru scriereif(fout==NULL) //se testeaza daca deschiderea fisierului s-a efectuat cu succes{printf("Eroare la deschiderea fisierului out.txt");getch();return;}while((c=fgetc(fin))!=EOF)fputc(c,fout); //scrierea in fisierul de iesire, a caracterului citit din fisierul de intrarefclose(fin); //inchiderea fisierului de intrare

Page 9: Fisiere Structuri de Date

fclose(fout); //inchiderea fisierului de iesireprintf("Copierea fisierului in.txt in fisierul out.txt s-a realizat cu succes");printf("\nApasati o tasta pentru a reveni in program !");getch();}b2) Scrierea unui şir de caractere într-un fişier. Aceasta se realizează utilizâ ndfuncţia fputs.Prototipul: fputs (const char *s, FILE *f)Ex:char sir[100];FILE *fis_out;//… … … .strcpy(sir,”Acest sir va fi scris in fisier”);fputs(sir,fis_out);//… … … ..b3) Functia fprintf.Prototipul: int fprintf(FILE *f, char *format, … )Dacă primul argument al funcţiei fprintf este stdout atunci datele vor fi scrise laieşirea standard(monitor)Ex:int n,m;n=2;m=4;FILE *fis_out;//… … … .fprintf(fis_out,”%d %d”,n,m);//… … … .3. Închiderea fişierului se realizează cu funcţia fclose.Prototipul: int fclose(FILE *f)Ex:FILE *fis_in;//… … … .fclose(fis_in);//… … … .