Přímá práce se soubory

V minulé lekci jsme s uloženými daty pracovali tak, že jsme je nejprve všechna načetli do pole, pole potom zpracovali a nakonec zase celé pole uložili. Tento způsob je náročný na operační paměť, protože jsou v ní uložena všechna zpracovávaná data, nehledě na problémy, které by způsobil výpadek proudu nebo systému (obsah operační paměti by mohl přijít vniveč :-) ). V této lekci si ukážeme druhý způsob, při kterém budeme pracovat přímo se souborem na disku - nebude potřeba žádné pole, operační paměť nebude zaplněna daty a při výpadku přijdeme přinejhorším o poslední neuložený záznam (pokud nepřijdeme o disk :-) ).

Při práci na dalším projektu využijeme tyto další procedury či funkce pro práci se soubory:
FileSize(soubor); - vrací celkový počet údajů (záznamů, komponent, položek) v souboru (nikoli velikost souboru v bytech!)
Seek(soubor, cislo); - nastavuje aktuální pozici v souboru na údaj (záznam, komponentu), jehož pořadí je určeno proměnnou cislo, položky jsou číslované od nuly!
Truncate(soubor); - vymaže všechny záznamy od aktuální pozice v souboru až do konce

Připomeňme si ještě příkazy pro čtení a zápis z minulé lekce, každé použití některého z těchto příkazů posune automaticky ukazatel v souboru o jednu položku dál:
read(soubor,proměnná) - přečte položku daného typu ze souboru a uloží do proměnné
write(soubor,proměnná) - uloží hodnotu proměnné do souboru

Projekt Závody

Náš další projekt je určen rozhodčím na závodech nebo soutěžích k evidenci závodníků, ti šikovnější z vás mohou zkusit projekt doplnit o zápis časů nebo bodů jednotlivých závodníků.

Nejprve nadefinujeme nový typ, do kterého budeme moci ukládat jméno, příjmení (případně čas) závodníka a potřebné proměnné, mezi nimi nesmí chybět proměnná typu soubor (část zdroje je uvedena jen proto, abyste si připomněli do které části kódu definice zapsat):

....
private
{ Private declarations }
public
{ Public declarations }
end;
type zaznam=record
jmeno:string[20];
prijmeni:string[20];
cas:integer;
end;

var
Form2: TForm2;
n, m, pocet: integer;
clen: zaznam;
soubor: file of zaznam;

Pro práci se souborem je dále potřeba proměnné typu soubor přiřadit konkrétní soubor na disku příkazem AssignFile, například hned při vytvoření formuláře:
procedure TForm2.FormCreate(Sender: TObject);
begin
AssignFile(soubor,'zavod.dat');
end;


Soubor je potřeba nejprve vytvořit (případně smazat starý) příkazem rewrite, v projektu je pro ten účel tlačítko Nový soubor:
procedure TForm2.Button2Click(Sender: TObject);
begin
rewrite(soubor);
listbox1.clear;
end;

Nyní už můžeme začít zapisovat závodníky, procedura na tlačítku zapsat by mohla vypadat takto:
procedure TForm2.Button1Click(Sender: TObject);
begin
clen.jmeno:=edit1.Text;
clen.prijmeni:=edit2.Text;
reset(soubor);
seek(soubor,filesize(soubor));
write(soubor,clen);
closefile(soubor);
vypis;
end;
Nejprve se z Editů načte do proměnné clen jméno a příjmení, otevře se soubor, další příkaz nastaví ukazatel na konec souboru, za poslední záznam se zapíše hodnota proměnné clen a soubor se zavře. Nakonec jsou položky souboru vypsané do listboxu pomocí procedury vypis (vzpomeňte si, co je potřeba pro definici nové procedury), tuto proceduru použijeme na více místech:
procedure TForm2.vypis;
begin
reset(soubor);
pocet:=filesize(soubor);
spinedit1.MaxValue:=pocet;
listbox1.Clear;
if filesize(soubor)>0 then
for n:=0 to pocet-1 do begin
seek(soubor,n); read(soubor,clen);
listbox1.Items.Add(inttostr(n+1)+'. '+clen.jmeno+' '+clen.prijmeni);
end;
closefile(soubor);
end;


Poměrně jednoduchá je procedura pro opravení jména závodníka, když ve SpinEditu je vybrané jeho číslo (podle výpisu - ten začíná od jedničky, ale čísla položek jsou od nuly!), data se zapisují vždy za položku, na které je ukazatel:
procedure TForm2.Button3Click(Sender: TObject);
begin
n:=spinedit1.value;
clen.jmeno:=edit3.Text;
clen.prijmeni:=edit4.Text;
reset(soubor);
seek(soubor,n-1); write(soubor,clen);
closefile(soubor);
vypis;
end;

Naopak nejsložitější bude procedura pro vymazání závodníka:
procedure TForm2.Button2Click(Sender: TObject);
begin
n:=spinedit1.value;
reset(soubor); pocet:=filesize(soubor);
if (n<=pocet) and (n>0) then begin
for m:=n+1 to pocet
do begin seek(soubor,m-1); read(soubor,clen); seek(soubor,m-2);
write(soubor,clen);end;
seek(soubor,pocet-1);Truncate(soubor);
vypis;
end;
end;
V proceduře se od zadaného záznamu až k poslednímu vždy přepíše položka tou následující (ve for cyklu). Po této úpravě souboru dojde k odmazání poslední položky.

Aplikace ukládej do složky s názvem lekce22 .

Úkoly:

Základní úloha:

Vytvoř projekt podle textu lekce a ukázky .


Úloha na plus:

V projektu je tlačítko pro načtení uloženého seznamu. Doplň příslušnou proceduru.


Úloha na jedničku:

Doplň možnost zadávání a oprav časů (nebo bodů) závodníků a vyhodnocení závodu (soutěže) - seřazení závodníků podle časů (bodů).

Úloha pro experty:

Doplň nabídky, možnost tisku či jiné možnosti, například podle ukázky .