Strona g│≤wna

 

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:

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.

Tutaj mo┐esz ╢ci▒gn▒µ gotowy skompilowany program:

TypedFiles.zip ( 3 kB )
Dane.zip ( 4 kB ) - przyk│ad prostej ksi▒┐ki adresowej;

Adam Boduch