Tutorial Pascal - Lectia 6 - Lucrul cu fisiere

Tutorial Pascal - Lectia 6 - Lucrul cu fisiere

Postby DarkByte » 25 Jan 2010, 02:44

Tutorial Pascal



Lucrul cu fisiere


Toate programele facute pana acum acceptau, ca sursa de date, tastatura, iar ca iesire, monitorul. Cu toate acestea, Pascal permite folosirea fisierelor.

Sunt convins ca v-ati intrebat, cel putin o data, de ce jocurile se instaleaza cu o multime de fisiere aditionale, in afara de executabilul propriu-zis. Raspunsul e simplu: resursele respectivului joc se afla in acele fisiere (harti, imagini, sunete, etc). Executabilul jocului citeste si scrie acele fisiere in functie de necesitati (scrie, de exemplu, in fisierul de high-scores).

Sa vedem cum putem folosi si noi fisiere, in Pascal.

Pentru inceput trebuie sa stiti ca Pascal ofera trei tipuri de fisiere:
  • fisiere text
  • fisiere cu tip
  • fisiere fara tip
Modul de lucru (accesare, citire, scriere) difera, cel putin partial, la fiecare tip de fisier.

Sa incepem cu inceputul.

Fisiere text in Pascal (text files)


Sa presupunem ca vrem sa citim doua numere de pe prima linie a unui fisier text, si apoi matricea cu respectivul numar de linii si coloane, dintr-un fisier text (creat cu notepad sau orice alternativa a acestuia). Fisierul ar putea avea urmatorul continut:


Sa vedem un program care citeste acest fisier si afiseaza datele citite pe monitor.
  1. uses crt;
  2. var fis: Text;
  3.     lins, cols, i, j: integer;
  4.     matrice: array[1 .. 20, 1 .. 20] of integer;
  5. begin
  6.   ClrScr;
  7.   Assign(fis, 'fisier.txt');
  8.   Reset(fis);
  9.  
  10.   ReadLn(fis, lins, cols);
  11.   for i := 1 to lins do
  12.     begin
  13.       for j := 1 to cols do
  14.         Read(fis, matrice[i, j]);
  15.       ReadLn(fis);
  16.     end;
  17.   Close(fis);
  18.  
  19.   WriteLn('Matricea citita din fisier este:'#13#10);
  20.   for i := 1 to lins do                    {#13#10 = Enter}
  21.     begin                                  {#13    = Carriage Return}
  22.       for j := 1 to cols do                {#10    = Line Feed}
  23.         write(matrice[i,j] : 3);
  24.       writeln;
  25.     end;
  26.   Write(#13#10'Apasati orice tasta pentru a iesi ...'#8#8#8#8);
  27.   ReadKey;                                          {#8 = BackSpace}
  28. end.

Declaratia unui fisier text se face identic cu declararea unei variabile obisnuite, iar tipul variabilei este Text. Fisier Text :P. Restul variabilelor nu are rost sa le explic, le puteti intelege daca ati parcurs tutorialele precedente.

Sa vedem ce proceduri si functii avem la dispozitie pentru lucrul cu fisiere text.
Proceduri si functii folosite la lucrul cu fisiere text
Nume
Descriere
Assign
Asigneaza un fisier (definit prin calea catre el) catre o variabila de tip fisier. Toate operatiile ulterioare care folosesc acel fisier vor utiliza variabila acestuia. Asocierea dintre variabila si respectivul fisier va exista pana la urmatoarea asignare a variabilei catre alt fisier.

Calea catre fisier trebuie sa fie o cale definita prin 0 sau mai multe directoare, separate prin semnul backslash \, urmate de numele complet al fisierului. Daca aceasta cale este inceputa direct cu semnul backslash, atunci este folosita ca si cum ar fi inceput direct in radacina ( C:\Folder\fisier.txt este identic cu \Folder\fisier.txt, daca programul este rulat dintr-un director de pe C:. Daca este dat doar numele fisierului, atunci fisierul este cautat in directorul curent (cel de unde este rulat programul).

Numele fisierului trebuie sa se conformeze standardului DOS de denumire a fisierelor, adica 8.3 (nume de maxim 8 caractere, fara spatii, si extensie (optionala) de maxim 3 caractere.

Un caz special este cel in care calea catre fisier este sirul vid (adica '' - doua apostroafe, unul dupa celalalt). In acest caz, variabila de fisier este asignata intrarii / iesirii standard. Dupa o asignare a variabilei catre sirul vid, folosirea procedurii Reset va asocia variabila catre intrarea standard, iar folosirea procedurii ReWrite va asocia aceasta variabila cu iesirea standard.

Restrictie:
  • procedura Assign nu poate fi folosita pe un fisier deja deschis.
Reset
Deschide un fisier existent pentru citire. Daca fisierul nu exista, aceasta procedura va genera o eroare.

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer-ul) este setata la inceputul acestuia (de acolo poate incepe citirea).

Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la intrarea standard (tastatura, de obicei).
Rewrite
Creaza un fisier nou si il deschide pentru scriere. Daca fisierul exista, atunci el este sters si recreat (gol). Daca variabila de fisier este asignata unui fisier deschis, acesta va inchis, sters, recreat si redeschis.

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer) este setata la inceputul acestuia.

Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei).
Append
Deschide fisierul ales (prin folosirea procedurii Assign) pentru scriere. Daca fisierul nu exista, atunci aceasta procedura va genera o eroare. Daca fisierul este deja deschis, atunci el este inchis si redeschis. Pozitia in fisier (file pointer) este setata la sfarsitul acestuia.

Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei).
Close
Inchide fisierul desemnat de variabila de fisier, daca respectivul fisier a fost deschis folosind una din procedurile Reset, Rewrite sau Append.

Fisierul asociat cu variabila de fisier este adus la zi cu toate modificarile operate asupra lui, inainte de a fi inchis.
EoLN
Aceasta functie (acronim de la End of LiNe) returneaza True daca pozitia in fisier (file pointer-ul) este la sfarsitul unei linii (marcaj #13#10) sau la sfarsitul fisierului. Returneaza False in caz contrar.

Functia poate fi apelata fara parametru sau cu un parametru de tip Text (fisier text). Daca este apelata fara parametru, atunci fisierul este considerat a fi fisierul standard de intrare (tastatura).
SeekEoLN
Verifica daca mai sunt date pe linia curenta, de la pozitia curenta pana la sfarsitul liniei. Daca nu mai sunt date pana la sfarsitul liniei (doar spatii sau tab-uri), va returna True, returnand False in caz contrar.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Poate fi folosita doar cu fisiere text.
EoF
Aceasta functie (acronim de la End of File) returneaza True daca pozitia in fisier (file pointer) este la sfarsitul fisierului. Returneaza False in caz contrar.

Functia poate fi apelata fara parametru sau cu un parametru de tip Text (fisier text). Daca este apelata fara parametru, atunci fisierul este considerat a fi fisierul standard de intrare (tastatura).
SeekEoF
Verifica daca mai sunt date in fisier, de la pozitia curent pana la sfarsitul fisierului. Daca nu mai sunt date pana la sfarsitul fisierului (doar spatii sau tab-uri), va returna True, returnand False in caz contrar.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Poate fi folosita doar cu fisiere text.

Daca ati trecut prin explicatiile date in tabelul de mai sus, ar trebui sa stiti destul de multe pentru a folosi un fisier text fara probleme.

Sa vedem un mic program care citeste prima linie dintr-un fisier text si o adauga, inversata, la sfarsitul fisierului.
  1. uses crt;
  2. var fis: Text;
  3.     linie: String;
  4.     i: integer;
  5.     c: Char;
  6. begin
  7.   ClrScr;
  8.   Assign(fis, 'fisier.txt');
  9.   Reset(fis);
  10.  
  11.   ReadLn(fis, linie);
  12.   WriteLn('Prima linie din fisier este urmatoarea:');
  13.   WriteLn(linie+#13#10);
  14.  
  15.   WriteLn('Vom adauga linia, inversata, in fisier, la sfarsitul acestuia.');
  16.   WriteLn;
  17.  
  18.   for i := 1 to Length(linie) div 2 do {bucla aceasta inverseaza sirul de caractere}
  19.     begin
  20.       c := linie[i];
  21.       linie[i] := linie[Length(linie) - i + 1];
  22.       linie[Length(linie) - i + 1] := c;
  23.     end;
  24.  
  25.   Append(fis);
  26.   WriteLn(fis, #13#10 + linie);
  27.   Close(fis);
  28.   Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...');
  29.   ReadKey;
  30. end.

Ultimul program care va folosi fisiere text in acest tutorial va citi date dintr-un fisier si le va salva in alt fisier.
  1. uses crt;
  2. var fis: Text;
  3.     linie: String;
  4.     i: integer;
  5.     c: Char;
  6. begin
  7.   ClrScr;
  8.   Assign(fis, 'fisier.in');
  9.   Reset(fis);
  10.  
  11.   ReadLn(fis, linie);
  12.   Close(fis);
  13.  
  14.   WriteLn('Prima linie din fisier este urmatoarea:');
  15.   WriteLn(linie+#13#10);
  16.  
  17.   Assign(fis, 'fisier.out');
  18.   Rewrite(fis);
  19.   WriteLn(fis, linie);
  20.   Close(fis);
  21.  
  22.   Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...');
  23.   ReadKey;
  24. end.

Atentie: presupun ca este evident ca toate fisierele de intrare folosite in aceste programe vor trebui create manual inainte de pornirea programului.

Fisiere cu tip in Pascal (typed files)


Acum, dupa ce-ati aflat ce-i cu fisierele text in Pascal, o sa-mi spuneti ca jocurile pe care le mentionam mai sus nu folosesc fisiere text, sau foarte rar... si nu va pot contrazice. Asa este.

Fisierele text, desi permit salvarea a orice date in ele, sunt limitate de faptul ca nu ne permit citirea unui anumit caracter, decat daca am citit toate caracterele dinaintea lui. Imaginati-va un fisier text de cativa megabytes (mega-octeti, daca vreti 8-|), din care vrem sa citim caracterul cu indicele 1.123.194 ... va trebui sa citim un milion de caractere inainte de a putea citi caracterul care ne intereseaza.

Aici intra in joc fisierele cu tip. Ele permit citirea secventiala a datelor (ca si fisierele text), dar si citirea aleatorie (random) din fisier. Spre deosebire de fisierele text, de unde puteam citi doar siruri de caractere (nu va lasati pacaliti de faptul ca ReadLn citeste si numere ... le converteste intern din string in valoare numerica !), din fisiere fara tip se pot citi doar valori de acelasi tip ca si fisierul in sine.

Fisierele cu tip sunt, practic, o varianta a vectorilor (array, if you please). Pot stoca date de un singur tip, cel setat in declararea variabilei de fisier, dar sunt limitate de spatiul disponibil pe hard-disk (si, in versiunile vechi de Pascal, cum ar fi Borland Pascal, de o marime maxima de 2 GB / fisier - tineti totusi cont ca in 1992, cand a aparut Borland Pascal 7.0 nu sunt sigur daca existau, inca, hard-disk-uri atat de mari !).

Haideti sa vedem un mic program care scrie un set de date aleatorii intr-un fisier cu tip (tip integer, pentru inceput), iar apoi le reciteste si afiseaza a 20-a valoare din fisier.
  1. uses crt;
  2. var fis: file of integer;
  3.     i, val: integer;
  4. begin
  5.   ClrScr;
  6.   Randomize;
  7.   Assign(fis, 'fisier.bin');
  8.   Rewrite(fis);
  9.  
  10.   for i := 1 to 100 do
  11.     begin
  12.       val := Random(20000) + 1; {valori intre 1 si 20000}
  13.       Write(fis, val);
  14.     end;
  15.   Close(fis);
  16.  
  17.   Assign(fis, 'fisier.bin');
  18.   ReSet(fis);
  19.   Seek(fis, 19); {indexul incepe de la 0}
  20.  
  21.   Read(fis, i);
  22.   WriteLn('A 20-a valoare din fisier este : ',i);
  23.  
  24.   Close(fis);
  25.  
  26.   Write(#13#10'S-a facut ! Apasati orice tasta pentru a iesi ...');
  27.   ReadKey;
  28. end.

Este de remarcat faptul ca fiecare element din fisier ocupa 2 bytes, in acest caz (integer).

Lista de proceduri si functii care pot fi folosite la manipularea fisierelor cu tip sunt date in tabelul de mai jos. Explicatiile date in acest tabel sunt doar complementare celor date in tabelul de proceduri si functii dat pentru folosirea cu fisiere text.
Proceduri si functii folosite la lucrul cu fisiere cu tip
Nume
Descriere
Assign
Identic cu fisierele text.
Reset
Deschide un fisier existent (pentru citire / scriere). Daca fisierul nu exista, aceasta procedura va genera o eroare.

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer-ul) este setata la inceputul acestuia.

Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la intrarea standard (tastatura, de obicei).
Rewrite
Creaza un fisier nou si il deschide (pentru scriere / citire). Daca fisierul exista, atunci el este sters si recreat (gol). Daca variabila de fisier este asignata unui fisier deschis, acesta va inchis, sters, recreat si redeschis.

Dupa ce fisierul a fost deschis, pozitia in fisier (file pointer) este setata la inceputul acestuia.

Daca variabila de fisier a fost asignata unui sir vid, dupa apelul acestei proceduri, variabila de fisier se va referi la iesirea standard (monitorul, de obicei).
Close
Inchide fisierul desemnat de variabila de fisier, daca respectivul fisier a fost deschis folosind una din procedurile Reset sau Rewrite.

Fisierul asociat cu variabila de fisier este adus la zi cu toate modificarile operate asupra lui, inainte de a fi inchis.
FileSize
Returneaza numarul de componente din fisierul desemna de variabila de fisier. Marimea actuala a fisierului poate fi aflata inmultind rezultatul acestei functii cu numarul de bytes folositi de fiecare componenta.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita cu fisiere text.
FilePos
Returneaza pozitia in fisier (file pointer-ul).

Daca pozitia este chiar la inceputul fisierului, atunci aceasta functie returneaza 0. Daca pozitia este la sfarsitul fisierului, atunci rezultatul lui FilePos este egal cu cel al functie FileSize, prezentata mai sus.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita cu fisiere text.
Seek
Muta pozitia in fisier (file pointer) la cea specificata. Urmatoarea citire sau scriere se face din acel loc.

Numarul primei componente din fisier este 0. Noua pozitie care poate fi specificata este de tip Longint, deci nu poate merge mai departe de 2 GB. Pentru a scrie la sfarsitul fisierului (dupa ultima componenta) se poate folosi cu impreuna cu rezultatul functiei FileSize.

Daca pozitia este chiar la inceputul fisierului, atunci aceasta functie returneaza 0. Daca pozitia este la sfarsitul fisierului, atunci rezultatul lui FilePos este egal cu cel al functie FileSize, prezentata mai sus.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita cu fisiere text.
Truncate
Trunchiaza fisierul de la pozitia curenta in fisier (file pointer). Toate componentele de dupa pozitia actuala in fisier sunt sterse.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita cu fisiere text.

Niciodata nu mi-a placut restrictia care spunea ca aceasta procedura / functie nu poate fi folosita cu fisiere text, asa ca am cautat o solutie. Solutia evidenta este sa folositi un fisier cu componente de tip Char (practic, text), putand astfel folosi si functii gen FileSize, FilePos, Seek, Truncate. Totusi, probabil ca ati vrea sa aveti grija la sfarsiturile de linie / fisier ;))

Fisiere fara tip in Pascal (untyped files)


Fisierele fara tip pot fi privite ca niste fisier cu tip byte, cu diferenta ca datele din aceste fisiere nu pot fi citite/scrise cu procedurile obisnuite (Read, Write), folosind BlockRead/BlockWrite, pentru transferuri la viteza mare.

Sa vedem ce s-a modificat si ce s-a adaugat, din punct de vedere al instructiunilor care pot fi folosite.
Proceduri si functii folosite la lucrul cu fisiere cu tip
Nume
Descriere
Assign
Identic cu fisierele cu tip.
Reset
In cazul fisierelor fara tip, aceasta procedura accepta si un parametru de tip Word, care specifica numarul de bytes avut de o componenta din fisier (RecSize). In mod implicit, RecSize este egal cu 128. Este preferabil sa il setati pe 1, avand astfel control absolut asupra citirilor / scrierilor facute in fisier.

Formatului apelului acestei proceduri este urmatorul:
  1. Reset(var F: File[; RecSize: Word]);
Rewrite
In cazul fisierelor fara tip, aceasta procedura accepta si un parametru de tip Word, care specifica numarul de bytes avut de o componenta din fisier (RecSize). In mod implicit, RecSize este egal cu 128. Este preferabil sa il setati pe 1, avand astfel control absolut asupra citirilor / scrierilor facute in fisier.

Formatului apelului acestei proceduri este urmatorul:
  1. Rewrite(var F: File[; RecSize: Word]);
Close
Identic cu fisierele cu tip.
FileSize
Identic cu fisierele cu tip.
FilePos
Identic cu fisierele cu tip.
Seek
Identic cu fisierele cu tip.
Truncate
Identic cu fisierele cu tip.
BlockRead
Citeste din fisierul selectat un numar specificat de bytes, intr-o variabila declarata de utilizator.

Formatul apelului este urmatorul:
  1. BlockRead(var F: File; var Buffer; Count: Word; [;var Result: Word]);

F este un fisier fara tip, Buffer poate fi orice variabila, Count este un numar intreg, iar Result este o variabila intreaga.

Aceasta functie citeste un numar de Count (sau mai putin) componente (marimea unei componente este specificata de Reset si Rewrite) din fisierul F in memorie, in variabila Buffer. Numarul de componente citite este returnat in variabila Result (daca este folosita). Daca variabila Result nu este folosita, o eroare I/O este generata in cazul in care numarul de componente citite este diferit de numarul specificat in apel (Count). Daca Result este egala cu Count, atunci operatia a avut efectul dorit.

Numarul de bytes cititi este, in cazul optim, Count * RecSize (RecSize este 128 de bytes, daca nu este specificat altfel). Daca numarul Count * RecSize este mai mare decat 65535 (64 KB), se va genera o eroare.

Pozitia in fisier este mutata la sfarsitul zonei citite, ca efect al instructiunii BlockRead.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita decat cu fisiere fara tip.
BlockWrite
Scrie in fisierul selectat un numar specificat de bytes, dintr-o variabila declarata de utilizator.

Formatul apelului este urmatorul:
  1. BlockWrite(var F: File; var Buffer; Count: Word; [;var Result: Word]);

F este un fisier fara tip, Buffer poate fi orice variabila, Count este un numar intreg, iar Result este o variabila intreaga.

Aceasta functie scrie un numar de Count (sau mai putin) componente (marimea unei componente este specificata de Reset si Rewrite) in fisierul F din memorie, din variabila Buffer. Numarul de componente scrise este returnat in variabila Result (daca este folosita). Daca variabila Result nu este folosita, o eroare I/O este generata in cazul in care numarul de componente scrise este diferit de numarul specificat in apel (Count). Daca Result este egala cu Count, atunci operatia a avut efectul dorit.

Numarul de bytes scrisi este, in cazul optim, Count * RecSize (RecSize este 128 de bytes, daca nu este specificat altfel). Daca numarul Count * RecSize este mai mare decat 65535 (64 KB), se va genera o eroare.

Pozitia in fisier este mutata la sfarsitul zonei scrise, ca efect al instructiunii BlockWrite.

Restrictii:
  • Fisierul trebuie sa fie deschis.
  • Nu poate fi folosita decat cu fisiere fara tip.


In continuare, un exemplu de program care copiaza un fisier (fara niciun fel de verificari).
  1. uses crt;
  2. var src, dest: file;
  3.     buffer: array[1 .. 32768] of byte; {buffer de 32 KB}
  4.     cale_src, cale_dest: string;
  5.     read_bytes: word;
  6. begin
  7.   ClrScr;
  8.   Write('Dati calea catre fisierul sursa: ');
  9.   ReadLn(cale_src);
  10.  
  11.   Write('Dati calea destinatie: ');
  12.   ReadLn(cale_dest);
  13.  
  14.   Assign(src, cale_src);
  15.   Reset(src, 1);
  16.  
  17.   Assign(dest, cale_dest);
  18.   Rewrite(dest, 1);
  19.  
  20.   While not Eof(src) Do {atat timp cat nu am ajuns la sfarsitul fisierului ...}
  21.     Begin
  22.       BlockRead(src, buffer, 32768, read_bytes); {vrem sa citim 32 KB, dar verificam cat am citit}
  23.       BlockWrite(dest, buffer, read_bytes); {cat am citit, atat scriem}
  24.     End;
  25.   Close(src);
  26.   Close(dest);
  27.   WriteLn(#13#10'Fisierul a fost copiat !');
  28.   ReadKey;
  29. end.

Daca fisierul care se doreste copiat nu exista, sau daca fisierul destinatie nu are extensie (lol :D) sau intervine orice alta problema, programul va returna erori. Nu este dat decat pentru a exemplifica un mod de lucru cu fisierele fara tip.
7p / 1 votes
User avatar
DarkByte
11011011
 
Joined: 29 Dec 2009
Status: 136

Return to Tutoriale Pascal

Who is online

Users browsing this forum: No registered users and 0 guests

cron