Pliki typowane
Zanim przeczytasz ten artyku│ powiniene╢ najpierw poczytaµ
artyku│ "Pliki", kt≤ry opisuje podstawowe operacje dotycz▒ce plik≤w.
Normalnie zapisuj▒c jakie╢ dane do pliku zapisujemy jaki╢ ci▒g
znak≤w. Pliki typowane natomiast nazywane s▒ czΩsto plikami rekordowymi
poniewa┐ s│u┐▒ do zapisywania rekord≤w. Przyk│adowo mo┐esz zapisaµ taki
oto rekord:
TVideoRec = packed record
NazwaFilmu : String[30];
Numerek : WORD;
Data : TDateTime;
end;
Teraz gdy mamy ju┐ odpowiedni rekord to nale┐y do niego
utworzyµ typ pliku:
TVideoFile = file of TVideoRec;
W taki spos≤b mo┐emy stworzyµ nasz unikalny, niepowtarzalny
system wymiany danych :) Tak, napiszemy teraz przyk│adow▒ aplikacjΩ, kt≤ra
gromadziµ bΩdzie informacje o wypo┐yczonym filmie, a nastΩpnie dane te bΩdzie
zapisywaµ do pliku. Tak wiΩc w jednym pliku bΩdziemy mieli dane, kt≤re bΩdzie
mo┐na p≤╝niej odczytaµ.
Zapisywanie danych do plik≤w typowanych odbywa siΩ tak samo
jak w przypadku zwyk│ych plik≤w tekstowych. Nie istnieje natomiast procedurΩ
"Append", kt≤ra jak zapewne pamiΩtasz ustawia│a pozycje do zapisu
bezpo╢rednio na ko±cu pliku. Taki co╢ w plikach typowanych nie wystΩpuje.
Nowe polecenia w plikach typowanych to: FileSize. To polecenie
pobiera ilo╢µ danych znajduj▒cych siΩ w pliku. W naszym przypadku ilo╢µ
rekord≤w wpisanych do pliku. Kolejne bardzo przydatne polecenie to Seek.
Ustawia ono plik na wybranej pozycji kt≤rej dotyczyµ bΩdzie kolejna operacja.
Czyli np:
Ustawia pozycje na drugim rekordzie ( w naszym wypadku ).
Jeszcze jedno polecenie to FilePos. Podaje ono pozycje na kt≤rej
teraz nastΩpuje operacja.
Nie martw siΩ je┐eli jeszcze wszystkiego nie rozumiesz.
Pozosta│e polecenie s▒ takie same jak w przypadku zwyk│ych
plik≤w.
Piszemy program...
Przyszed│ czas, aby napisaµ program, kt≤ry korzysta│ bΩdzie
z plik≤w typowanych. Jakie komponenty bΩd▒ nam potrzebne? Umie╢µ na formie
komponent typu "TComboBox" oraz 2 kontrolki typu "TEdit",
"TDateTimePicker" oraz "TButton".
Na pocz▒tek przyjmiemy, ┐e plik, do kt≤rego bΩd▒ zapisywane
dane bΩdzie siΩ nazywa│ "Dane.dat":
const
FileName = 'Data.dat'; // tutaj przechowywane beda informacje...
Na samy pocz▒tek potrzebna nam bΩdzie procedura odczytuj▒ca
ilo╢µ rekord≤w zawartych w pliku. Oto ona - ilo╢µ danych bΩdzie dodawany
do kontrolki "cmbRec" [ TComboBox ]:
procedure TMainForm.RefreshRec;
var
VFile : TVideoFile;
I : Integer;
begin
{
Ta procedura ma za zadanie odswiezyc liste rekordow znajdujacych
sie w danym pliku. Zawartosc komponentu najpierw zostaje czyszczona,
a pozniej nastepuje odczytanie wszystkich rekordow i dodanie ich do listy.
}
AssignFile(VFile, FileName);
if not FileExists(FileName) then // Jezeli plik nie istnieje - nie rob nic
Exit else
Reset(VFile);
cmbRec.Items.Clear; // czysc liste danych w komponencie
{
Ponizsza petla ma za zadanie dodawanie kolejnych pozycji do listy.
"FileSize" zawiera informacje o ilosci rekordow znajdujacych sie
w pliku.
}
For I := 0 to FileSize(VFile) -1 do
cmbRec.Items.Add('Rekord nr: ' + IntToStr(i));
CloseFile(VFile);
end;
Zauwa┐, ┐e tutaj znalaz│o zastosowanie u┐ycie polecenia
"FileSize". Ale zacznijmy od pocz▒tku. Jako zmienne zadeklarowane
zosta│y dwie - pierwsza wskazuje na nowy typ pliku [ zadeklarowali╢my j▒ na
pocz▒tku ]. Pozosta│e polecenia s▒ takie same jak w przypadku plik≤w
tekstowych. Dochodzimy do pΩtli, kt≤ra wykonywana zostaje tyle razy ile jest
rekord≤w za ka┐dym razem dodaj▒c numer tego┐ rekordu do listy.
To ju┐ mamy - teraz najwa┐niejsze, czyli sama procedura
zapisuj▒ca rekord do pliku:
procedure TMainForm.WriteDate;
var
VFile : TVideoFile; // zmienna wskazuje na nowy typ plikow
VRec : TVideoRec; // zmianna wskazuje na rekord
FSize : Integer; // ilosc danych znajdujacych sie w pliku...
begin
AssignFile(VFile, FileName); // skojarz nazwe pliku ze zmienna...
if not FileExists(FileName) then // jezeli plik nie istnieje...
Rewrite(VFile) else //... stworz go, a jezeli istnieje...
Reset(VFile); //... tylko otworz
try
FSize := FileSize(VFile); // pobierz rozmiar ( ilosc danych )
if FSize > 0 then // Czy plik nie jest pusty?
Seek(VFile, FSize); // ustaw na samym koncu pliku
{
Dodaj do rekordu dane wziete z kontrolek tekstowych znajdujacych
sie na formie.
}
with VRec do
begin
NazwaFilmu := edtFname.Text;
Numerek := StrToInt(edtNumber.Text);
Data := Date.DateTime;
end;
Write(VFile, VRec); // zapisz rekord do pliku
finally
CloseFile(VFile); // zamknij plik
RefreshRec; // wywolaj procedure ( patrz: linia 140 )
end;
end;
Na samym pocz▒tku sprawdzane jest, czy plik zosta│ utworzony,
czy te┐ nie. Je┐eli nie to go tworzy. P≤╝niej zmienna "FSize"
przechowuje liczbΩ rekord≤w znajduj▒cych siΩ w pliku. Kolejno nastΩpuje
ustawienie siΩ na samym ko±cu pliku ( polecenie "Seek" ). NastΩpnie
wype│nienie rekordu danymi znajduj▒cymi siΩ w kontrolkach no i w ko±cu
zapisanie ca│ego rekordu na samym ko±cu. Zauwa┐, ┐e przy ko±cu procedury
nastΩpuje wywo│anie innej - "RefreshRec", kt≤ra odczytuje ilo╢µ
rekord≤w ( teraz zapisali╢my nowy wiΩc ta liczba siΩ zwiΩkszy│a ).
Na samym ko±cu procedura odczytuj▒ca rekord. Procedura ta
zawieraµ bΩdzie jeden prarametr - w nim bΩdzie informacja o tym, kt≤ry
rekord chcemy odczytaµ:
procedure TMainForm.ReadData(NumberOfRec: Byte);
var
VFile : TVideoFile;
VRec : TVideoRec;
begin
{
Ta procedura odczytuje rekord. Jako parametr tej procedury podawany
jest numer rekordu, ktory ma byc odczytany.
}
AssignFile(VFile, FileName);
Reset(VFile);
try
Seek(VFile, NumberOfRec); // ustaw na danym rekordzie....
Read(VFile, VRec); // odczytaj rekord
{ Teraz dane znajduja sie w rekordzie i nalezy je przypisac do kontrolek }
with VRec do
begin
edtFName.Text := NazwaFilmu;
edtNumber.Text := IntToStr(Numerek);
Date.DateTime := Data;
end;
finally
CloseFile(VFile); // zamknij plik
end;
end;
W tym wypadku polecenie "Seek" ustawia na pozycji kt≤rej
numer odpowiada numerowi zawartemu w zmiennej "NumberOfRec".
Je┐eli czego╢ nie rozumiesz to pisz,
a tutaj masz ca│y kod programu:
(****************************************************************)
(* *)
(* Przykladowy program korzystajacy z plikow typowanych *)
(* Copyright (c) 2001 by Adam Boduch *)
(* All rights reserved by Service for programmers *)
(* HTTP://WWW.PROGRAMOWANIE.OF.PL *)
(* E - mail: boduch@poland.com *)
(* Build: 01.04.2001 r. *)
(* *)
(****************************************************************)
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls;
type
TMainForm = class(TForm)
grbInfo: TGroupBox;
lblName: TLabel;
edtFName: TEdit;
lblNumber: TLabel;
edtNumber: TEdit;
lblDate: TLabel;
Date: TDateTimePicker;
btnSave: TButton;
cmbRec: TComboBox;
procedure cmbRecChange(Sender: TObject);
procedure btnSaveClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure ReadData(NumberOfRec : Byte);
procedure WriteDate;
procedure RefreshRec;
end;
{
Ponizszy rekord przechowuje informacje o kliencie. Zapisywany on
bedzie do pliku...
}
TVideoRec = packed record
NazwaFilmu : String[30]; // nazwa filmu
Numerek : WORD; // numer klienta
Data : TDateTime; // data wypozyczenia
end;
TVideoFile = file of TVideoRec; // wskazanie na rekord [ nowy typ ]
var
MainForm: TMainForm;
implementation
const
FileName = 'Data.dat'; // tutaj przechowywane beda informacje...
{$R *.DFM}
procedure TMainForm.WriteDate;
var
VFile : TVideoFile; // zmienna wskazuje na nowy typ plikow
VRec : TVideoRec; // zmianna wskazuje na rekord
FSize : Integer; // ilosc danych znajdujacych sie w pliku...
begin
AssignFile(VFile, FileName); // skojarz nazwe pliku ze zmienna...
if not FileExists(FileName) then // jezeli plik nie istnieje...
Rewrite(VFile) else //... stworz go, a jezeli istnieje...
Reset(VFile); //... tylko otworz
try
FSize := FileSize(VFile); // pobierz rozmiar ( ilosc danych )
if FSize > 0 then // Czy plik nie jest pusty?
Seek(VFile, FSize); // ustaw na samym koncu pliku
{
Dodaj do rekordu dane wziete z kontrolek tekstowych znajdujacych
sie na formie.
}
with VRec do
begin
NazwaFilmu := edtFname.Text;
Numerek := StrToInt(edtNumber.Text);
Data := Date.DateTime;
end;
Write(VFile, VRec); // zapisz rekord do pliku
finally
CloseFile(VFile); // zamknij plik
RefreshRec; // wywolaj procedure ( patrz: linia 140 )
end;
end;
procedure TMainForm.ReadData(NumberOfRec: Byte);
var
VFile : TVideoFile;
VRec : TVideoRec;
begin
{
Ta procedura odczytuje rekord. Jako parametr tej procedury podawany
jest numer rekordu, ktory ma byc odczytany.
}
AssignFile(VFile, FileName);
Reset(VFile);
try
Seek(VFile, NumberOfRec); // ustaw na danym rekordzie....
Read(VFile, VRec); // odczytaj rekord
{ Teraz dane znajduja sie w rekordzie i nalezy je przypisac do kontrolek }
with VRec do
begin
edtFName.Text := NazwaFilmu;
edtNumber.Text := IntToStr(Numerek);
Date.DateTime := Data;
end;
finally
CloseFile(VFile); // zamknij plik
end;
end;
procedure TMainForm.cmbRecChange(Sender: TObject);
begin
{
Jezeli uzytkownik z listy dostepnych rekordow wybierze jakis
do nastepuje wywolanie procedury, ktora ma odczytac rekord.
Jako parametr podawany jest indeks w komponencie "cmbRec".
}
ReadData(cmbRec.ItemIndex);
end;
procedure TMainForm.btnSaveClick(Sender: TObject);
begin
{ Po nacisnieciu przycisku wywolaj procedure }
WriteDate;
end;
procedure TMainForm.RefreshRec;
var
VFile : TVideoFile;
I : Integer;
begin
{
Ta procedura ma za zadanie odswiezyc liste rekordow znajdujacych
sie w danym pliku. Zawartosc komponentu najpierw zostaje czyszczona,
a pozniej nastepuje odczytanie wszystkich rekordow i dodanie ich do listy.
}
AssignFile(VFile, FileName);
if not FileExists(FileName) then // Jezeli plik nie istnieje - nie rob nic
Exit else
Reset(VFile);
cmbRec.Items.Clear; // czysc liste danych w komponencie
{
Ponizsza petla ma za zadanie dodawanie kolejnych pozycji do listy.
"FileSize" zawiera informacje o ilosci rekordow znajdujacych sie
w pliku.
}
For I := 0 to FileSize(VFile) -1 do
cmbRec.Items.Add('Rekord nr: ' + IntToStr(i));
CloseFile(VFile);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
RefreshRec; // wywolaj procedure
end;
end.
Tutaj mo┐esz ╢ci▒gn▒µ gotowy skompilowany program:
TypedFiles.zip
( 3 kB )
Dane.zip
( 4 kB ) - przyk│ad prostej ksi▒┐ki adresowej;
Adam Boduch