Strumienie

Adam Boduch

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ść:

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.

4 komentarzy

Lipa, mialo byc o strumieniach, a tu zapisywanie plikow :/ A o TMemoryStream i TStringStream zapomniałes?

Jest w Download Delphi
pod nazwą Dane (Poprawione)
tu link bezposredni
http://4programmers.net/download.php?id=275

pewnie w dziale Programy!!!

skad wziac ten kod do "Kartoteki" ???