Pliki typowane
Adam Boduch
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:
Seek(F, 2);
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.
Zobacz też:
Powiedzcie mi jeszcze, jak mogę edytować już istniejące rekordy.
Bo na razie próbuję zrobić tak że ustawiam plik na tym rekordzie który chcę zmienić ale zamiast tego zmienia mi się następny. Niby wystarczy cofnąć o 1 ale wtedy nie da się edytować pierwszego rekordu...
Poniewaz nie wszystkie bitmapy sa takiego samego rozmiaru.
Jakoś nie działa mi ta sztuka na zmiennych typu TBitmap. Wie ktoś może dlaczego pojawia mi sie błąd "Acces violation"?
Mam pytanie: Czy w ten sposob ładują sie wszystkie rekordy do pamieci? Czy też jest ładowany aktualnie potrzebny (przez itemindex)?
Dobre, przydatne do większości programów z obsługą plików! I bez szyfrowania :P
Artykol naprewde przydatny dla tych, ktozy chca zrobic (zalozyc) wlasny system plikow !
[quote]wlasny system plikow[/quote] rotfl