Strumienie

Strona g│≤wna

 

Strumienie

Co to s▒ te strumienie? Jak by to najpro╢ciej wyja╢niµ? Ot≤┐ strumienie to ci▒g danych, kt≤ry mo┐e byµ zapisywany np. w pliku. Wyobra╝ sobie tak▒ ksi▒┐kΩ adresow▒. Masz na formie listΩ adres≤w oraz imion zgrupowanych np. na komponencie typu ListView. Chcesz te adresy teraz zapisaµ tak jak to ma miejsce np. w Windowsowej ksi▒┐ce adresowej. Na ko±cu tego artyku│u bΩdzie rozwi▒zanie tego problemu - zapisywanie wszystkiego do jednego pliku i odczytanie. A wszystko za pomoc▒ strumieni. 

Podstawow▒ klas▒ dla strumieni jest klasa TStream. To od niej wywodz▒ siΩ pozosta│e obiekty bΩd▒ce samodzielnym typem. Oto one:

  • TFileStream - s│u┐y do operacji na plikach;

  • TMemoryStream - do operacji danych w pamiΩci komputera;

  • TResourceStream - operuje na zasobach plik≤w;

  • TStringStream - s│u┐y do operacji na zmiennych tekstowych ( String ).

W tej chwili pewnie nie wiesz jak to wszystko zastosowaµ itp. Ale nie martw siΩ - zaraz wszystko stanie siΩ jasne gdy┐ wykorzystanie strumieni nie jest niczym nadzwyczajnym. 

Np. wykorzystanie typu TResourceStream. Oto przyk│ad wyci▒gniΩcia z naszego programu EXE bitmapy o nazwie 'MOJA', a nastΩpnie zapisanie tej bitmapy na dysku:

var
  S : TResourceStream;
begin
  S := TResourceStream.Create(hInstance, 'MOJA', RT_BITMAP);
  S.SaveToFile('C:\main.bmp');
  S.Free;

Sam przyznasz, ┐e to nie jest nic trudnego, prawda? Najpierw deklarowana jest zmienna typu "TResourceStream", a nastΩpnie jest ona tworzona. W konstruktorze zmiennej pierwszym parametrem jest uchwyt pliku, drugim nazwa zasobu, a ostatni parametr to typ zasobu. Typy zasob≤w mo┐esz poznaµ w systemie pomocy Delphi pod zak│adk▒ "TResourceStream". 

No i nastΩpnie wyci▒gniΩty zas≤b zostaje zapisany na dysku. 

Tak jak opisa│em wy┐ej strumienie mog▒ tak┐e operowaµ na plikach. Trzeba jednak podaµ w≤wczas tryb otwarcia pliku - np:

var
  S : TFileStream;
begin
  S := TFileStream.Create('C:\plik.txt', fmOpenWrite);

Pierwszym parametrem tego konstruktora jest nazwa pliku, kt≤rego bΩdzie dotyczyµ operacja, a drugim parametrem jest w│a╢nie tryb otwarcia. Ten parametr mo┐e mieµ nastΩpuj▒c▒ warto╢µ:

Parametr Opis
fmCreate Tworzy nowy plik je┐eli nie istnieje na dysku;
fmOpenRead Otwiera plik jedynie do odczytu;
fmOpenWrite Otwiera plik do zapisu;
fmOpenReadWrite Otwiera do zapisu lub do odczytu;

ªwietnie - je┐eli masz ju┐ plik otwarty mo┐esz przyst▒piµ do operacji na tym w│a╢nie pliku. 

Podstawowymi funkcjami s▒ polecenia zapisu i odczytu. Robi▒ to funkcje zapisu i odczytu:

  • Write, WriteBuffer - zapisuje dane do pliku;

  • Read, ReadBuffer - odczyt;

R≤┐nica pomiΩdzy dwoma poleceniami wykonywuj▒cymi tΩ sam▒ czynno╢µ jest taka, ┐e polecenia Read i Write to funkcje i zwracaj▒ liczbΩ danych wpisanych do pliku. Przyk│adowy zapis rekordu do pliku m≤g│by wygl▒daµ tak: 

var
  S : TFileStream;
  Rec : record
    Name : String;
    ID : Byte;
  end;
begin
  Rec.Name := 'Adam';
  Rec.ID := 2;
  S := TFileStream.Create('C:\plik.txt', fmCreate);
  S.WriteBuffer(Rec, SizeOf(Rec));
  S.Free;

To spowoduje zapis danych do pliku. Mo┐esz teraz np. dopisaµ do istniej▒cych danych kolejny rekord - s│u┐y do tego polecenie Seek:

  S := TFileStream.Create('C:\plik.txt', fmOpenWrite);
  S.Seek(SizeOf(Rec), soFromEnd);

W tym wypadku polecenie Seek przesunie miejsce zapisu danych na sam koniec. Pierwszym parametrem jest wielko╢µ danych - okre╢lone jest to poprzez SizeOf. Kolejny parametr to miejsce w kt≤rym ma siΩ rozpocz▒µ operacja zapisu. W tym wypadku bΩdzie to na samym ko±cu pliku. Mo┐esz w tym miejscu podaµ dowoln▒ warto╢µ lub: 

  • soFromBeginning - na samym pocz▒tku;

  • soFromCurrent - aktulne miejsce;

  • soFromEnd - sam koniec;

 

Do okre╢lenia ilo╢ci rekord≤w znajduj▒cych siΩ w pliku mo┐esz zastosowaµ co╢ takiego:

  Rozmiar := S.Size div SizeOf(Rec);

Zmienna Rozmiar bΩdzie zawieraµ ilo╢µ rekord≤w. Zasada jest prosta: w│a╢ciwo╢µ Size okre╢la ilo╢µ bajt≤w zapisanych w pliku - dziel▒c to przez rozmiar ( w bajtach ) rekordu otrzymamy ilo╢µ rekord≤w znajduj▒cych siΩ w pliku.

Istnieje jeszcze polecenie Position, kt≤ra okre╢la aktualn▒ pozycje w pliku. 

To w│a╢ciwie wszystko co najwa┐niejsze. 

Strumienie umo┐liwiaj▒ tak┐e zapisywanie do pliku ustawie± komponent≤w - np. po│o┐enia komponentu na formie itp. Do tego s│u┐▒ polecenia: WriteComponent oraz ReadCompoennt.

ProszΩ bardzo - zapisanie komponentu o nazwie "btnMove" do pliku:

var
  FileStream : TFileStream;
begin
  if FileExists('setup.txt') then // jezeli istnieje plik
    FileStream := TFileStream.Create('setup.txt', fmOpenWrite) else
  FileStream := TFileStream.Create('setup.txt', fmCreate); //w przeciwnym wypadku stworz plik

  FileStream.WriteComponent(btnMove); // zapisz ustawienia komponentu TButton
  FileStream.Free; // zwolnij zmienna

W tym wypadku je┐eli plik nie istnieje to zostanie stworzony, a je┐eli istnieje - zostanie jedynie otwarty do zapisu. 

Teraz odczyt wygl▒da bardzo podobnie: 

procedure TMainForm.FormCreate(Sender: TObject);
var
  FileStream : TFileStream;
begin
  if not FileExists('setup.txt') then Exit; //jezeli plik nie istnieje - nie rob nic
  
  FileStream := TFileStream.Create('setup.txt', fmOpenRead); //otworz tylko do odczytu
  FileStream.ReadComponent(btnMove);  // odczytaj ustawienia komponentu
  FileStream.Free;
end;

Istnieje jeszcze jedna przydatna funkcja - CopyFrom. Przedstawia siΩ ona nastΩpuj▒co:

function CopyFrom ( Source: TStream; Count: Longint ) : Longint; 

S│u┐y ona do przypisania jednemu strumieniowi warto╢ci drugiego strumienia. 

Polecam ╢ci▒gniΩcie ╝r≤d│a programu "Kartoteka", kt≤ry wykorzystuj▒c strumienie zapisuje do pliku nazwΩ oraz e-mail. Jest to taka ksi▒┐ka adresowa. 

Przydatne linki:

  • Klasy - opis klas - jak siΩ je tworzy?

¼r≤d│a:

  • Dane.zip ( 174 kB ) - ksi▒┐ka adresowa;

  • Stream.zip ( 2 kB ) - przyk│ad wykorzystania strumieni; 

Adam Boduch