Datele din memorie dispar la terminarea programului. Fișierele sunt structuri de date organizate pe suporturi externe, care permit păstrarea informației între execuții și schimbul de date între aplicații.
1Obiectivele lucrării
- Clasificarea fișierelor după conținut, acces și tipul operațiilor permise
- Deschiderea și închiderea corectă a unui fișier, cu verificarea reușitei
- Alegerea modului potrivit de deschidere
- Citirea și scrierea în fișiere text și binare
- Poziționarea în fișier pentru acces direct
2Clasificarea fișierelor
| Criteriu | Categorii | Descriere |
|---|---|---|
| După conținut | fișiere text | caractere organizate pe linii; sfârșitul liniei marcat prin <CR><LF> |
| fișiere cu tip | înregistrări de un anumit tip, elementar sau structurat | |
| fișiere fără tip | fișiere binare, secvențe brute de octeți | |
| După acces | acces secvențial | informația se prelucrează doar în ordinea înregistrării |
| acces direct | componentele pot fi prelucrate în orice ordine, după poziționare | |
| După operații | de intrare | doar citire |
| de ieșire | doar scriere | |
| de intrare/ieșire | ambele - posibilă actualizarea informației |
Marcajul de sfârșitSfârșitul unui fișier este semnalat printr-un marcaj special
numit EOF (end of file). Funcțiile de citire îl returnează pentru a indica faptul că nu mai
există date.
3Deschidere și închidere
Orice transfer este precedat de operația de deschidere, care creează un stream și îl asociază
fișierului. Se folosește o variabilă de tip FILE * și se alocă automat o zonă tampon
prin care se fac transferurile.
tiparul corect
FILE *f = fopen("date.txt", "r"); // 1. deschidere
if (f == NULL) { // 2. VERIFICARE obligatorie
printf("Nu pot deschide fisierul!\n");
return 1;
}
/* ... citire sau scriere ... */ // 3. prelucrare
fclose(f); // 4. inchidere
De ce este obligatorie închidereaDatele scrise stau într-o zonă tampon și ajung
pe disc abia când aceasta se umple sau la
fclose. Dacă programul se termină fără închidere,
ultimele date scrise se pot pierde. În plus, numărul de fișiere deschise simultan este limitat.| Funcție | Rol |
|---|---|
fopen(nume, mod) | deschide fișierul; returnează NULL la eșec |
fclose(f) | golește tamponul și închide fișierul |
feof(f) | testează dacă s-a atins sfârșitul fișierului |
ferror(f) | testează dacă a apărut o eroare |
fflush(f) | forțează scrierea tamponului pe disc |
remove(nume) | șterge fișierul |
rename(vechi, nou) | redenumește fișierul |
4Modurile de deschidere
| Mod | Semnificație | Dacă fișierul există | Dacă nu există |
|---|---|---|---|
"r" | citire | se deschide de la început | eroare (NULL) |
"w" | scriere | se șterge tot conținutul! | se creează |
"a" | adăugare | se scrie la sfârșit | se creează |
"r+" | citire și scriere | se deschide de la început | eroare |
"w+" | citire și scriere | se șterge tot conținutul | se creează |
"a+" | citire și adăugare | scrierea se face la sfârșit | se creează |
Se adaugă litera b pentru fișiere binare ("rb", "wb",
"ab") și t pentru text, acesta fiind modul implicit.
Cel mai periculos mod este "w"Deschiderea unui fișier existent cu
"w"
îi șterge instantaneu tot conținutul, chiar dacă nu se scrie nimic după aceea. Pentru adăugare la
un fișier existent folosiți "a".5Operații cu fișiere text
| Nivel | Citire | Scriere |
|---|---|---|
| Caracter | fgetc(f), getc(f) | fputc(c, f), putc(c, f) |
| Linie / șir | fgets(s, n, f) | fputs(s, f) |
| Cu format | fscanf(f, "...", ...) | fprintf(f, "...", ...) |
Corespondența cu funcțiile de consolăFiecare funcție de fișier are un echivalent
pentru consolă:
fprintf ↔ printf, fscanf ↔ scanf,
fgets ↔ gets. Diferența este primul parametru, care indică streamul.
printf(...) este echivalent cu fprintf(stdout, ...).Atenție la feofFuncția
feof devine adevărată doar după o
citire eșuată, nu înainte. Bucla while (!feof(f)) { fscanf(...); ... } prelucrează ultima
înregistrare de două ori. Corect: while (fscanf(f, "%d", &x) == 1) { ... }6Operații cu fișiere binare
prototipuri
size_t fread (void *p, size_t dim, size_t nr, FILE *f); size_t fwrite(const void *p, size_t dim, size_t nr, FILE *f); // p - adresa zonei din memorie // dim - dimensiunea unei inregistrari, in octeti // nr - cate inregistrari se transfera // f - streamul // returneaza numarul de inregistrari transferate efectiv
| Aspect | Fișier text | Fișier binar |
|---|---|---|
| Conținut | caractere lizibile | copie exactă a reprezentării din memorie |
| Numărul 12345 | 5 caractere (5 octeți) | 4 octeți (un int) |
| Editare manuală | posibilă în orice editor | practic imposibilă |
| Viteză | mai lentă (conversii) | rapidă, fără conversii |
| Portabilitate | bună | limitată (endianness, padding) |
7Acces direct - poziționarea în fișier
| Funcție | Rol |
|---|---|
fseek(f, offset, origine) | mută indicatorul de poziție |
ftell(f) | returnează poziția curentă, în octeți |
rewind(f) | revine la începutul fișierului |
| Constantă pentru origine | Punct de referință |
|---|---|
SEEK_SET | începutul fișierului |
SEEK_CUR | poziția curentă |
SEEK_END | sfârșitul fișierului |
Citirea înregistrării cu numărul n
fseek(f, n * sizeof(Inregistrare), SEEK_SET); urmat de fread(...).
Acesta este avantajul major al fișierelor binare cu înregistrări de dimensiune fixă: orice element
se accesează direct, fără a parcurge tot fișierul.8Cod sursă
text_scriere.c - creare și adăugare
#include <stdio.h>
int main(void)
{
FILE *f = fopen("date.txt", "w"); // ATENTIE: sterge continutul existent
if (f == NULL) {
printf("Nu pot crea fisierul!\n");
return 1;
}
fprintf(f, "Popescu Ion;20;9.15\n");
fprintf(f, "Ionescu Maria;21;8.70\n");
fprintf(f, "Georgescu Radu;20;9.60\n");
fclose(f);
printf("Fisier creat.\n");
// adaugare la sfarsit, fara stergerea continutului
f = fopen("date.txt", "a");
if (f) {
fprintf(f, "Dumitrescu Ana;22;9.85\n");
fclose(f);
printf("Inregistrare adaugata.\n");
}
return 0;
}
text_citire.c - parcurgere corectă
#include <stdio.h>
int main(void)
{
FILE *f = fopen("date.txt", "r");
if (f == NULL) {
printf("Fisierul nu exista!\n");
return 1;
}
char linie[200];
int nrLinii = 0;
// varianta corecta: conditia este chiar reusita citirii
while (fgets(linie, sizeof(linie), f) != NULL) {
nrLinii++;
printf("%3d: %s", nrLinii, linie);
}
printf("\nTotal %d linii\n", nrLinii);
fclose(f);
// citire cu format, camp cu camp
f = fopen("date.txt", "r");
char nume[50];
int varsta;
float medie;
printf("\nCitire structurata:\n");
while (fscanf(f, "%49[^;];%d;%f\n", nume, &varsta, &medie) == 3) {
printf(" %-20s %3d ani media %.2f\n", nume, varsta, medie);
}
fclose(f);
return 0;
}
binar.c - scrierea și citirea structurilor
#include <stdio.h>
typedef struct {
char nume[50];
int varsta;
float medie;
} Student;
int main(void)
{
Student grupa[3] = {
{"Popescu Ion", 20, 9.15f},
{"Ionescu Maria", 21, 8.70f},
{"Georgescu Radu", 20, 9.60f}
};
// scriere binara: tot tabloul, dintr-un singur apel
FILE *f = fopen("studenti.dat", "wb");
if (!f) return 1;
fwrite(grupa, sizeof(Student), 3, f);
fclose(f);
// citirea inregistrarii cu numarul 1 (a doua), FARA a citi prima
f = fopen("studenti.dat", "rb");
if (!f) return 1;
Student unul;
fseek(f, 1 * sizeof(Student), SEEK_SET); // pozitionare directa
fread(&unul, sizeof(Student), 1, f);
printf("Inregistrarea 1: %s, %d ani, media %.2f\n",
unul.nume, unul.varsta, unul.medie);
// dimensiunea fisierului
fseek(f, 0, SEEK_END);
long dim = ftell(f);
printf("Dimensiune fisier: %ld octeti = %ld inregistrari\n",
dim, dim / (long)sizeof(Student));
fclose(f);
return 0;
}
copiere.c - copierea unui fișier, octet cu octet
#include <stdio.h>
int main(void)
{
FILE *sursa = fopen("date.txt", "rb");
if (!sursa) { printf("Sursa lipseste\n"); return 1; }
FILE *dest = fopen("copie.txt", "wb");
if (!dest) { fclose(sursa); return 1; }
char tampon[1024];
size_t citite;
long total = 0;
// se copiaza in blocuri, mult mai rapid decat octet cu octet
while ((citite = fread(tampon, 1, sizeof(tampon), sursa)) > 0) {
fwrite(tampon, 1, citite, dest);
total += citite;
}
printf("Copiati %ld octeti\n", total);
fclose(sursa);
fclose(dest);
return 0;
}
9Atelier de cod
Casetele de mai jos au un sistem de fișiere propriu, care există doar în pagină. Fișierele scrise de un program pot fi citite imediat după aceea de același program.
De încercatSchimbați modul din
"w" în "a" (adăugare) și rulați de două ori: veți vedea că liniile se adaugă la sfârșit în loc să înlocuiască fișierul.De încercatFișierul
poezie.txt există deja în sistemul de fișiere al acestei casete.10Sarcini de lucru
- Creați un fișier text cu date despre studenți și citiți-l apoi linie cu linie.
- Deschideți un fișier existent cu modul
"w"și observați ce se întâmplă cu conținutul. - Adăugați înregistrări noi folosind modul
"a", fără a pierde datele vechi. - Numărați liniile, cuvintele și caracterele dintr-un fișier text.
- Scrieți un tablou de structuri într-un fișier binar și citiți doar a treia înregistrare.
- Comparați dimensiunea aceleiași informații salvate în format text și în format binar.
- Implementați copierea unui fișier folosind un tampon de 1024 de octeți.
- Testați diferența dintre
while (!feof(f))șiwhile (fscanf(...) == n).
11Aplicație de aprofundare
ExtindereImplementați o agendă telefonică persistentă, cu fișier binar de
înregistrări de dimensiune fixă: adăugare, căutare după nume, modificarea unei înregistrări existente
(prin
fseek și rescriere pe loc, fără a recrea fișierul) și ștergere logică printr-un câmp
indicator. Adăugați o funcție de „compactare" care elimină fizic înregistrările marcate ca șterse.