artykuły

Delphi - Strumienie - Informacje dodatkowe

20:36
Sat, 9 October 2004
Ostatnia część z serii artykułów o strumieniach danych w Delphi. Zawiera uzupełnienie informacji oraz ciekawostki związane z opisywanym zagadnieniem.

#Informacje dodatkowe

Wstęp

Cały cykl artykułów "Delphi - strumienie" miał za zadanie zademonstrować w prosty sposób użycie poszczególnych typów tych użytecznych narzędzi. Nie obyło się jednak bez pewnych specyficznych "haczyków", które miały sposobność dokuczać w większości początkującym w tej dziedzinie. Dziś przedstawię informacje, których nie znaleźliście wcześniej. Będzie to uzupełnienie do poprzednich części artykułów, jak i zarazem ostatnia część cyklu.

Polecenie Seek

Omówię jako pierwsze właśnie to polecenie. Służy ono bowiem do zmiany pozycji kursora w pliku. Jak zapewne wiecie, przy opracowywaniu różnorakich dokumentów (np. poprzez Word, WordPad, AbiWord czy Notatnik) mamy do czynienia z kursorem. To taka "migająca pionowa kreseczka" (ujął by ktoś to bardziej fachowo ? ;). Dzięki niej, zawsze wiemy w którym miejscu w dokumencie aktualnie się znajdujemy, a tym samym gdzie pojawi się nowowpisywany tekst. Również w pamięciowych plikach, jakimi są zapewne strumienie, mamy do czynienia z takim zjawiskiem. Również tu, możemy wyobrazić sobie kursor tak jak to zostało opisane wcześniej. Dzięki niemu będziemy mogli kontrolować, gdzie mamy zamiar umieścić zapisywane dane. Polecenie Seek, jako takie ma trzy parametry, z których możemy w każdej chwili skorzystać. Oto one:

Tabela 1.1 - opisy możliwych parametrów pozycji funkcji Seek()
Parametr Opis
parametr pełniona funkcja
soFromBeginning  Przenosi kursor na początek strumienia.
soFromCurrent  Przenosi kursor do aktualnej pozycji Position.
soFromEnd Przenosi kursor na koniec strumienia.
Aby udowodnić przydatność tej instrukcji, skupmy się na poniższym przykładzie. Poniższy przykładowy program zapisuje informacje w strumieniu typu TMemoryStream, a następnie próbuje je odczytać (mniejsza o użyteczność tego kodu). Problem jednak w tym, że po zapisaniu zawartości komponentu Memo1 do strumienia, kursor zostaje przesunięty na sam koniec. Zatem aby odczytać jakiekolwiek dane, musimy cofnąć kursor na początek naszych danych. Właśnie do tego posłuży nam instrukacja Seek. Spójrzcie na poniższy przykład. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type   TForm1 = class(TForm)     Button1: TButton;     Memo1: TMemo;     Button2: TButton;     procedure Button1Click(Sender: TObject);     procedure Button2Click(Sender: TObject);     private       { Private declarations }     public       { Public declarations }     end; var   Form1: TForm1;   strumien : TMemoryStream; implementation {$R *.dfm} procedure TForm1.Button2Click(Sender: TObject); begin   // Zapisanie danych do strumienia   memo1.Lines.SaveToStream(strumien);   // Wyczyszczenie komponentu Memo1   memo1.Clear; end; procedure TForm1.Button1Click(Sender: TObject); begin   // Po zapisie kursor jest na końcu strumienia dlatego cofamy go na początek   strumien.Seek(0, soFromBeginning);   // Odczytanie danych ze strumienia   memo1.Lines.LoadFromStream(strumien); end; initialization   strumien := TMemoryStream.Create; end. Powyższy kod powinien bezproblemowo przejść przez łaski kompilatora ;) i równie bezproblemowo powinien działać w praktyce. Spróbujcie jednak wyrzucić polecenie:strumien.Seek(0, soFromBeginning);a program działać przestanie. Jak widzimy polecenie Seek() z powyższymi parametrami, cofa kursor na początek strumienia, dzięki czemu możemy odczytać dane. Co oznacza jednak pierwszy parametr ? Spróbujmy to wywnioskować z ogólnej budowy polecenia:function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;Na miejscu pierwszego prarametru widzimy nijakie "Offset". Jest to parametr który określa o ile ma zostać przesunięty kursor w stosunku do pozycji podanej w drugim parametrze. Mogło to zabrzmieć nieco niejasno, dlatego przytoczę przykład. Gdy wywołamy funkcję Seek z parametrami:Seek(5, soFromBeginning);będzie to oznaczało, że umieszczamy kursor w strumieniu po piątym znaku licząc od początku. Przypuśćmy, że w strumieniu znajduje się tekst "Magazyn". Gdy wywołamy polecenie Seek() z parametrami Seek(0, soFromBeginning) i spróbujemy odczytać tekst ze strumienia, odczytane zostaną wszystkie dane, od początku, aż do końca, czyli "Magazyn". Gdybyśmy jednak wywołali funkcję Seek() z parametrami Seek(2, soFromBeginning) w wyniku próby odczytu dostaniemy jedynie "gazyn". Jak zatem odczytać np. trzy ostatnie litery? Polecenie Seek() wywołane z parametrami Seek(0, soFromEnd); na niewiele się zda, ponieważ przesunie nam kursor na koniec strumienia, a za końcem nie ma już nic ;) Popatrzmy jeszcze raz na budowę Seek(). Szczególną uwagę zwróćmy na typ pierwszego parametru, jest to int64, a jak wiemy typ ten może przechowywać również wartości ujemne. Dlatego chcąc odczytać 3 ostatnie znaki musimy wywołać polecenie Seek() z parametrami:Seek(-3, soFromEnd);Spowoduje to cofnięcie kursora o trzy miejsca "w lewo", czyli do tyłu, licząc od końca.

Właściwość Position

Co ciekawe instrukcja:Seek(0, soFromBeginning);może zostać zastąpiona bardziej precyzyjną właściwością Position:Position := 0;Analogicznie instrukcja np. Seek(84, soFormBeginning); jest równoznaczna z przypisaniem:Position := 84;Czy nie łatwiej? Wydaje mi się, że tak.

Właściwość Size...

... jest właściwością tylko do odczytu i przechowuje aktualny rozmiar danych w strumieniu. W przypadku tekstu, każdy znak to, jak sobie przypominamy, jeden bajt. Dlatego w wypadku tekstu "Ala ma kota" właściwość Size będzie równa 11. Proste? Jasne, że tak. Dzięki temu możemy zastąpić polecenie:Seek(0, soFromEnd);przypisaniem:Position := Size;Zatem gdy chcielibyśmy odczytać dane od środka strumienia musimy podzielić rozmiar strumienia przez dwa:Position := Size div 2;

Zakończenie

To już wszystko na dzisiaj. Wspomnę jeszcze tylko o funkcji CopyFrom(). Jej budowa jest następująca:CopyFrom(Source: TStream; Count: Int64): Int64;Za jej pomocą możecie kopiować dane z jednego do drugiego strumienia (jako pierwszy parametr podajemy strumień z którego chcemy skopiować dane, drugi parametr służy do określania wielkości danych które chcemy skopiować). Dodaje do artykułu źródło, w którym pokazałem jak efektownie wykorzystać funkcje CopyFrom(). Aha, jeszcze jedna przydatna informacja! Jeśli w drugim parametrze funkcji CopyFrom() wpiszecie 0 to skopiuje się cała zawartość strumienia źródłowego.
To wszystko! Spotykamy się za miesiąc.

12345
Delphi - Strumienie - Informacje dodatkowe Autor opinii: Czytelnicy, data przesłania: 0

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    Nie ma jeszcze żadnych komentarzy.
    Dexter