Delphi - Strumienie - TStringStream
Mon, 12 July 2004
#2 TStringStream
Wstęp
Wiele jest rzeczy w Delphi, z których nigdy nie skorzystamy - zapewniam Was, że strumienie do nich nie należą. Strumieniem którym się zajmiemy w niniejszej części jest strumień typu TStringStream. Kto "uważnie przejrzał" ;) pierwszą część cyklu, wie zapewne, że umożliwia on przeprowadzanie operacji na zmiennych tekstowych. Ten który zaczął od razu od części #2 może to samo wywnioskować z nazwy. No dobrze, ale w czym ten strumień może nam pomóc. Oczywiście, zamiast prawić rozległe teorię, proponuje skorzystać z przykładu w celu ustabilizowania wiedzy zawartej w połączeniach post-synaptycznych waszych neuronów (nie martwcie się - ja też nie rozumiem ;) Innymi słowy popatrzcie na przykład :
Aby zadeklarować strumień typuTStringStreamnależy dopisać po słówku var:
var
strumien : TStringStream;
Niestety taki kod nie będzie jeszcze działać. Do tej pory
"powiedzieliśmy" kompilatorowi, że gdzieś w kodzie będziemy
chcieli skorzystać z takiej zmiennej. Należy jeszcze zmienną utworzyć.
Zapytacie pewnie dlaczego jeśli chcemy zadeklarować zmiennąxjakointegernie tworzymy jej, a zmienną typuTStringStreammusimy stworzyć aby jej użyć?
var
x : integer;
begin
x := 17;
Zauważcie, że jest między nimi spora różnica, jedno zawiera na początku
literęT, a dokładniejTStringStream. Ktoś kiedyś rzekł, żeTnależy pisać
przed nazwami klas. Tak się przyjęło i tak jest do tej pory. Klasy zawsze
tworzymy po zadeklarowaniu. Tak więc
musicie zapamiętać - ten typ tak ma ;)
Wracamy do tematu. Aby przygotować naszą zmiennąstrumiendo użycia w pełnym
tego słowa znaczeniu, musimy zmienną stworzyć (wszyscy wiedzą dlaczego).
Piszemy więc :
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
Jak widzimy, po słówkuvardeklarujemy zmiennąstrumientypuTStringStream. Następnie tworzymy ją poprzez przypisanie :
strumien := TStringStream.Create('do czego służy ten tekst?');
Takie przypisanie pozwoli nam już skorzystać z możliwości jakie oferuje
namTStringStream. Zanim zaczniemy odkrywać nowe możliwości tego rozwiązania,
przypatrzmy się budowie funkcjiTStringStream.Create(), czyli tak zwanegokonstruktora.
Prezentuje się ona następująco:
TStringStream.Create(AString: string);
Zastanowiła Was pewnie jedna rzecz. Co należy wpisać w miejsceAString :
string? Jak widzimy,AStringjest zmienną łańcucha znakówstring, więc
jako parametr musimy nadać jakiś tekst. Ale do czego nam on posłuży ? Hmm...
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
...co by się stało gdybyśmy teraz dopisali jakąś funkcję, która sczyta
nam zawartość naszego strumienia i wyświetli go np. w komunikacie? Zobaczmy :
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
ShowMessage(strumien.DataString);
strumien.Free;
3-cia linia, a właściwie 5-ta, zawiera w sobie dziwne polecenie -DataString. Do czego może ono służyć? Spróbujmy uruchomić program (F9). I
co? Otrzymaliśmy komunikat "do czego służy ten tekst?". I co? Wiemy
już do czego służy łańcuch znakówAStringużyty przy tworzeniu naszego
strumienia i domyślamy się również znaczenia poleceniaDataString.
Łańcuch znaków, który musimy podać przy tworzeniu strumienia służy do
nadania jakiejś początkowej zawartości naszemu strumieniowi. Możemy wpisać
jako parametr coś takiego:strumien := TStringStream.Create('');
Spowoduje to utworzenie pustego strumienia.
PolecenieDataStringjak się zapewne domyślacie pozwala nam odczytać całą
zawartość strumienia. W naszym wypadku wartość nadaną przy tworzeniu
strumienia, czyli "do czego służy ten tekst?".
Oczywiście na końcu naszego krótkiego programu musimy zwolnić strumień.
Warto tego przestrzegać, choć w przypadku pojedynczej procedury (gdzie raz
sczytujemy czy zapisujemy dane) jest to nieobowiązkowe. Pamiętać jednak nie
zawadzi. Dlatego zachęcam do zwalniania strumieni po ich użyciu. W ten sposób
unikniemy przykrych niespodzianek przy uruchamianiu programu.
Write
Co jednak w przypadku gdy chcemy zapisać do strumienia jakieś
nowe dane? W takim przypadku posługujemy się poleceniemWrite. Ma ono następującą
budowę:function Write(const Buffer; Count: Longint): Longint;
Jak widzimy jest to funkcja. Analogicznie jak w przypadku strumieni typuTFileStreamzwraca ona ilość zapisanych danych. Pierwszy parametr przechowuje
dane do zapisania, natomiast drugi parametr ilość danych które funkcja ma
zapisać.
Gdy jako parametry funkcji podamy:zapisane := strumien.Wrtie('Magazyn @t', 3);
Zapisze ona do strumienia tylko słowo:
MagAby tak się nie działo możemy zastosować następującą składnię:
zapisane := strumien.Write('Magazyn @t', Length('Magazyn @t'));
Spowoduje to zapisanie całego tekstu przeznaczonego do zapisania. Zmienna
'zapisane' zawiera w tym wypadku ilość danych zapisanych do pliku.
Pisanie jednak dwa razy tego samego tekstu w funkcji jest bardzo niewygodne, dlatego opracowano procedurę:
WriteString
Procedura ta, podobnie jak jej siostra zapisuje do pliku
tekst. Jest jednak mała różnica - nie zwraca ona żadnych danych (jest
procedurą), ani nie potrzebuje określania wielkości zapisywanych danych.
Jedynym jej parametrem jest tekst jaki ma zapisać do strumienia. Przyjrzyjmy się
zatem budowie tej bardzo praktycznej procedury:procedure WriteString(const AString: string);
Korzystamy z niej w następujący sposób :strumien.WriteString('Magazyn @t');
To wszystko, nic nie trzeba więcej robić! Co prawda dużo częściej będziecie
korzystać z proceduryWriteStringniż ze zwykłej funkcjiWrite, ale ważna
jest znajomość obu tych metod.
Pokuszę się o modyfikacje naszego programu :
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
strumien.WriteString('Magazyn @t');
ShowMessage(strumien.DataString);
strumien.Free;
Teraz uważajcie! Komunikat który się wyświetli po starcie tego programu
nie będzie wbrew pozorom zwierał tekstu:do czego służy ten tekst?Magazyn @t
...ale w zawartości komunikatu pojawi się samo:Magazyn @t
Dlaczego? Otóż wartość początkowa nadawana przy tworzeniu strumienia ma
to do siebie, że jest usuwana wraz z pierwszym zastosowaniem jakiejś funkcji
zapisującej (np.WriteString). Gdybyśmy jednak dodali kolejną linię :
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
strumien.WriteString('Magazyn @t');
strumien.WriteString('-numer 42');
ShowMessage(strumien.DataString);
strumien.Free;
...to nasz komunikat wyświetliłby coś takiego:Magazyn @t-numer 42
Jak widać na powyższym przykładzie, usuwanie poprzedniej wartości
przez funkcję zapisującą dotyczy tylko i wyłącznie wartości początkowej
nadawanej przy tworzeniu strumienia. Mam nadzieję, że rozumiecie.
Zanim jednak ostatecznie przydusimy klawisz F9, radzę popatrzeć na funkcję
odczytujące dane ze strumienia. Pierwszą z nich jest funkcjaRead, następna
toReadStringi właściwośćDataString.
Read
Funkcjareadsłuży do odczytu danych z pliku. Jej budowa
prezentuje się następująco:function Read(var Buffer; Count: Longint): Longint;
Jak widzimy - pierwszym parametrem jest tzw. bufor, czyli zmienna, która będzie
przechowywała odczytane już dane. Drugim parametrem jest ilość danych które
mają zostać odczytane. Funkcjareadzwraca ostatecznie ilość udanie
odczytanych danych (w bajtach). Aby z niej skorzystać musimy zadeklarować
najpierw zmienną, która będzie buforem, a po słowiebeginumieścić funkcjęRead, która odczyta nam zawartość strumienia.
Aby odczytać całą zawartość, funkcja może mieć jako drugi parametr podaną
maksymalną wielkość danych jaką zmiennabufor_tekstowyjest zdolna w sobie
zmieścić :SizeOf(bufor_tekstowy);
Gwarantuje nam to odczytanie wszystkich danych. Oczywiście gdybyśmy chcieli
odczytać tylko trzy pierwsze litery - nie ma problemu, wystarczy tylko jako
drugi parametr funkcjiReadpodać 3.
Oczywiście tak jak w przypadku funkcji zapisujących, istnieje prostsza metoda,
mianowicie funkcjaReadStringlub właściwośćReadData.
ReadString
Funkcja ta, pozwala nam odczytywać zawartość strumienia dużo
prościej, bo bez deklarowania niepotrzebnych zmiennych. Popatrzcie jak jest
zbudowana:function ReadString(Count: Longint): string;
Jak widzimy, pierwszym i jedynym parametrem funkcji jest ilość danych do
odczytania. Ostatecznie funkcja zwraca odczytane dane. Jak jednak odczytać przy
pomocy tej funkcji całą zawartość strumienia ? Spróbujcie tak :
var
strumien : TStringStream;
begin
strumien := TStringStream.Create('do czego służy ten tekst?');
strumien.WriteString('Magazyn @t');
strumien.Position := 0;
ShowMessage(strumien.ReadString(strumien.Size));
strumien.Free;
Pewnie zauważyliście nową instrukcję -Position. Zapomniałem wcześniej
zaznaczyć, określa ona aktualną pozycję kursora w strumieniu. Jeśli zatem
chcemy czytać od początku ustawiamy :strumien.Position := 0;
Jeśli tego nie zrobimy - klapa. Domyślacie się dlaczego? FunkcjaWriteString()przesuwa nam kursor o tyle miejsc ile zapisuje liter tekstu. Zatem
po wykonaniu funkcjiWriteString, w powyższym przypadku kursor utknie na 10-siątej
pozycji i stąd (wzwyż) będzie próbowała następnie odczytać dane funkcjaReadString(), dlatego nic nie zobaczymy w komunikacie. O właściwościPosition,
tak jak iSeekorazSizebyć może powiemy sobie jeszcze w ostatniej części
cyklu. Póki co wyjaśnię jeszcze co zawiera właściwośćstrumien.Size;
Otóż za jej pomocą odczytamy wielkość danych w strumieniu. Czyli w tym
wypadku 10.
DataString
Właściwość (tak, tak właściwość)DataStringpozwala nam odczytać całą zawartość strumienia za pomocą jednej instrukcji. Przechowuje ona dane zawarte w strumieniu. Możemy ją wykorzystywać jako zmienną, ale tylko do odczytu. Nie da się w niej zapisywać żadnych danych.
Zakończenie
Jest wiele innych funkcji, które pozwalają sprawnie operować na strumieniach. W tym cyklu postaram się wyróżnić te najważniejsze. Będę przekazywał również przydatne porady, które pozwolą Wam zaoszczędzić czas na "odkrywaniu" rzeczy odkrytych nie zawsze przyjemną metodą prób i błędów. Wiem ile czasu może stracić programista na szukaniu odpowiedniego rozwiązania. Tutaj jednak żaden podręcznik, żaden kurs, żaden artykuł nie będzie lepszy od wypróbowanej już nauki na błędach...
Podobne artykuly:
- Delphi - Strumienie - Wstęp
- Delphi - Strumienie - TFileStream
- Delphi - Strumienie - TMemoryStream
- Delphi - Strumienie - TResourceStream
- Delphi - Strumienie - Informacje dodatkowe
- KillAd
- Delphi - Budowa modułu