1. Filekezelés
Gyakran szükség lehet arra, hogy a memóriában lévõ adatokat lemezre írjuk, vagy lemezen lévõ adatokat olvassunk be. A lemezen lévõ adatok file-okban helyezkednek el. Egy adatszerkezet mûködését a benne lévõ adatok típusán kívül az is meghatározza, hogy miképpen tudunk bele adatot írni, vagy belõle adatot olvasni. Noha egy file minden esetben byte-ok sorozata, a file-okat kétféle módon kezelhetjük.
A szekvenciális (soros szerkezetû) file mûveletei:
Így tehát egy ilyen file második elemét csak úgy olvashatjuk be, hogy elõtte beolvassuk az elsõ elemét. Egy szekvenciális file-t vagy csak írásra, vagy csak olvasásra nyithatunk meg.
A közvetlen elérésû, más néven direkt file fix hosszúságú elemek, más néven rekordok sorozata. Mivel így pontosan kiszámítható, hogy a file valahányadik rekordja melyik byte-nál kezdõdik, ebben a file-ban akárhányadik rekordra ráállhatunk. A direkt file mûveletei:
Ha a direkt file-t megnyitottuk, abból olvashatunk is, és írhatunk is bele.
A Pascalban a fenti mûveleteken kívül lekérdezhetõ még, hogy kiolvastuk-e már az utolsó elemet a file-ból (vagyis vége van-e a file-nak).
A file-okat elõször deklarálni kell, mint a változókat:
A szekvenciális file a Pascalban TEXT típusú. A file sorokból áll, melyeket újsor-jel választ el. Vagyis ez nem más, mint egy közönséges szöveges file. Az elõnye a direkt file-hoz képest, hogy pontosan úgy lehet kezelni, mint amikor a billentyûzetrõl olvasunk be adatokat, vagy a képernyõre írunk. A szöveges file szerkezete nem függ a programozási nyelvtõl, tehát egy más program által elõállított szöveges file-t (ez lehet pl. számok sorozata) Pascal programmal fel tudunk dolgozni. A legtöbb adatkezelõ program (szövegszerkesztõ, táblázatkezelõ) képes szöveges file-ba is kiírni az adatokat.
Mivel a direkt file-nál meg kell adnunk egy alaptípust, és a Pascal alaptípusai a STRING típust kivéve mind fix hosszúságúak (vagyis meghatározott számú byte-ból állnak), máris biztosítottuk a fix rekordhosszt. (Ha a file alaptípusa STRING, akkor minden egyes rekord a lehetõ leghosszabb lesz, vagyis 255 karakter, mert ez a string típus maximális hossza).
Elõször is, a file-hoz hozzá kell rendelnünk egy DOS filenevet. Ezt végzi el az
utasítás. Ezután a file-ra mindig a deklarációnál megadott névvel hivatkozunk, a DOS-os névre nincs többé szükség. Új file-t hoz létre a
utasítás. Ez az új, üres file-t írásra nyitja meg. Már meglévõ file-t a
utasítással nyithatunk meg. Ez szekvenciális file-nál csak olvasásra nyitja meg a file t, direkt file-nál írásra- olvasásra. Csak szekvenciális file-nál használható az
utasítás, mely írásra nyit meg létezõ file-t, és a végére áll (hozzáfûzés).
A file-ba való írás és a belõle olvasás eltér a két filetípusnál. Szekvenciális (TEXT) file ugyanúgy használható, mint a képernyõ, csak meg kell adni, hogy melyik file-ba írunk, vagy melyiket olvassuk:
Direkt file-nál nincs értelme sorokról beszélni, ott tehát nem használható a READLN és WRITELN utasítás. További különbség, hogy WRITE használata esetén is a kifejezés helyett változót kell használni - természetesen csak olyan változót, amelynek típusa megegyezik a file alaptípusával. Tehát:
A file-ból való olvasás közben folyamatosan vizsgálnunk kell, hogy nincs-e még vége a file-nak. Erre való az
függvény, melynek értéke TRUE, ha már kiolvastuk a file utolsó elemét.
Végül a file-t le is kell zárnunk. Ennek az az oka, hogy a file-ba akár byte-onként is írhatjuk az adatokat, a DOS azonban a file-nak egyszerre egy szektorát kezeli (ez legtöbbször 512 byte). Tehát nem írja fel azonnal az adatokat a file-ba, hanem megvárja, míg összegyûlik az 512 byte, és ezt egyetlen mûvelettel írja fel. Az adatokat a lemezre írásig úgynevezett pufferben tárolja. Ha a file-t lezárjuk, a puffert felírja a lemezre, akár összegyûlt benne a szükséges adat, akár nem. Ha a lezárás elmarad, a file vége is lemaradhat. File lezárása:
A következõ példaprogram direkt file adatokkal való feltöltésére mutat példát.
TYPE Ember=Record
nev:string[20];
szul:integer;
End;
VAR f:file of Ember;
r:Ember;
BEGIN
Assign(f,'nyilv.dat');
Repeat
Write('Név: ');
Readln(r.nev);
If r.nev<>'*' then begin
Write('Született: '); Readln(r.szul);
Write(f,r);
End;
Until r.nev='*'
Close(f);
END.
Érdemes megfigyelni a programban, hogy külön típust hoztunk létre a file rekordjainak. Erre azért volt szükség, hogy az r változó típusa (amely segítségével a file-ba írunk) ugyanaz lehessen, mint a file alaptípusa.
Nézzük meg, hogy hogyan lehetne a file-ban tárolt adatokat beolvasni a memóriába.
CONST Max=1000;
VAR t:Array[1..Max] of Ember;
i:integer;
BEGIN
Assign(f,'nyilv.dat');
Reset(f);
i=0;
While (not Eof(f)) and i<Max do begin
i=i+1;
Read(f,t[i]);
End;
Close(f);
END.
A Max konstanst úgy válasszuk meg, hogy nagyobb legyen a file várható hosszánál. A tömb méretét ugyanis elõre deklarálni kell, a file hosszát pedig nem ismerjük elõre. Ennek ellenére a ciklusfeltételben vizsgáljuk, hogy fér-e még adat a tömbbe, így a program túl hosszú file esetén sem áll le, csak nem olvassa be a file fennmaradó részét. i változó tartja nyilván, hogy hány elemet olvastunk be a file-ból. Azért használtunk elöltesztelõs ciklust, hogy ha a file üres, akkor a program ne próbáljon meg olvasni belõle.
A következõ (nagyon tipikus) program két file-t kezel: az elsõ file-ból a 100-nál nagyobb számokat átválogatja a másik file-ba.
VAR f,g:file of integer;
a:integer;
BEGIN
Assign(f,'egyik.dat');
Assign(g,'masik.dat');
Reset(f);
Rewrite(g);
While not Eof(f) do begin
Read(f,a);
If a>100 Then Write(g,a);
End;
Close(g);
Close(f);
END.
Az eddigi programok, bár direkt file-okkal dolgoztak, csak a szekvenciális file-ok lehetõségeit használták. A következõ program már csak direkt file-okkal mûködik: egy file-ban a negatív számok helyére 0-t ír. A file-ból egyszerre olvasunk, és írunk is bele. Ehhez szükség lesz a következõ eljárásokra és függvényekre (csak haladóknak!)
VAR f:file of real;
a:real;
BEGIN
Assign(f,'szamok.dat');
Reset(f);
While not eof(f) do begin
Read(f,a);
If a<0 Then Begin
Seek(f,filepos(f)-1); {visszalépünk
egy rekorddal}
Write(f,0); {és
annak helyére írjuk a 0-t}
End;
End;
Close(f);
END.
Végül nézzünk egy példát szöveges file kezelésére: a file számokat tartalmaz, a program ezeket összegzi. A bemeneti szöveges file-t akármilyen szöveges editorral elõállíthatjuk.
VAR f:Text;
s,a:integer;
BEGIN
Assign(f,'szoveg.txt');
Reset(f);
s=0;
While not eof(f) do begin
Readln(f,a);
s=s+a;
End;
Close(f);
Writeln('Az öszeg: ',s);
END.