Strumienie

Strumienie umożliwiają dostęp do dowolnej uporządkowamej struktury danych, niezależnie od zródła tych danych. Strumienie są używane do odczytu i zapisu zarówno wewnętrznych jak i zewnętrznych struktur danych (m.in. ciągów znaków, plików, zewnętrznych serwerów (połączeń sieciowych), kolekcji, procesów itp.) przy użyciu ustandaryzowanego interfejsu. Są one także używane do dostępu do dużych porcji danych, bez konieczności wczytywania całych objektów do pamięci komputera.

Tworzenie strumieni

Strumienie są najczęściej tworzone dla konkretnych obiektów:

ReadStream on: ‘abcd’.
WriteStream on: OrderedCollection new.
‘readme.txt‘ asFilename readStream.
‘Ala ma kota‘ writeStream.

Operacje na strumieniach

Strumienie dzielą się na strumienie tylko do odczytu oraz do zapisu. W strumieniach do odczytu można zmieniać położenie wkaznika kolejnego elementu, w strumieniach do zapisu jest to niemożliwe. Jeżeli programista potrzebuje zmiany położenia wskażnika w trakcie zapisu (na przykład do nadpisania już istniejących elementów), to musi on użyć strumienia do odczytu i zapisu.

Odczyt

next

Kolejne elementy strumienia odczytujemy za pomocą metody next.

stream := ReadStream on: 'Ala ma kota.'.
stream next.

Powyższy kod zwróci jako wynik znak $A (egzemplarz klasy Character). Kolejne wywołanie polecenia stream next zwróci $l, kolejne $a itd aż do osiągnięcia końca strumienia. Po osiągnięciu końca strumienia kolejne wywołanie metody next spowoduje zależnie od implementacji wystąpienie błędu lub zwrócenie wartości nil.

atEnd

To, czy wskaznik kolejnego elementu wskazuje już na koniec strumienia można sprawdzić przy pomocy metody atEnd.

stream := ReadStream on: ’a’.
stream atEnd. ”false, ponieważ wskaznik pokazuje $a.”
stream next.
stream atEnd. ”true, ponieważ wskaznik pokazuje koniec strumienia.”

next:

Można także odczytać dowolną ilość kolejnych elementów za pomocą metody next:

stream := ReadStream on: 'Ala ma kota'.
stream next: 6.

Powyższy kod zwróci ciąg znaków ‘Ala ma’.

Jeżeli w strumieniu nie ma żądanej ilości elementów, to wystąpi błąd. Dlatego dostępna jest kolejna metoda nextAvailable:

nextAvailable:

Metoda nextAvailable: zwraca zadaną ilość elementów strumienia. Jeżeli strumień nie posiada żądanej ilości elementów, to zwróconych zostanie tyle, ile jest dostępnych.

stream := ReadStream on: 'Ala ma kota'.
stream nextAvailable: 600.

Powyższy kod zwróci ciąg znaków ‘Ala ma kota’.

through: i throughAll:

Meoda through: zwraca elementy od aktualnej pozycji wskaznika odczytu do pierwszego wystąpienia obiektu będącego argumentem tej metody, włącznie z tym obiektem.

stream := ReadStream on: 'Ala ma kota'.
stream through: Character space.

Powyższy kod zwróci ciąg znaków ‘Ala ’ (ze spacją włącznie).

Jeżeli żądany element nie zostanie znaleziony w strumieniu, to metoda ta zwróci zawartość strumienia od bieżącej pozycji wskaznika do końca strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream through: $x.

Wynikiem wykonania tego kodu będzie ciąg znaków ‘Ala ma kota’.

Wariantem tej metody jest throughAll:, jej argumentem jest kolekcja elementów.

stream := ReadStream on: 'Ala ma kota'.
stream throughAll: 'ma'.

Wynikiem tego kodu będzie ciąg znaków ‘Ala ma’.

Jeżeli żądana kolekcja nie zostanie znaleziona w strumieniu, to metoda ta zwróci zawartość strumienia od bieżącej pozycji wskaznika do końca strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream throughAll: 'ona'.

Wynikiem wykonania tego kodu będzie ciąg znaków ‘Ala ma kota’.

peekFor:

Jeżeli kolejny obiekt w strumieniu jest równy argumentowi metody peekFor:, to metoda ta zwraca wartość true i przesuwa wskaznik za ten element. W przeciwnym wypadku metoda ta zwraca wartość false, a wskaznik nie ulega zmianie.

stream := ReadStream on: 'Ala ma kota'.
stream peekFor: $A.
stream next.

W powyższym przykładzie metoda peekFor: znalazła znak $A, wskaznik został przesunięty i metoda next zwraca kolejny element, czyli znak $l.

stream := ReadStream on: 'Ala ma kota'.
stream peekFor: $X.
stream next.

W tym przykładzie metoda peekFor: nie znajduje znaku $X, wskaznik się nie zmienia, a metoda next zwraca znak $A.

upTo:

Meoda upTo: zwraca elementy od aktualnej pozycji wskaznika odczytu do pierwszego wystąpienia obiektu będącego argumentem tej metody, ale bez tego obiektu. Wskaznik odczytu zostaje ustawiony za znalezionym obiektem.

stream := ReadStream on: 'Ala ma kota'.
stream upTo: Character space.
stream next.

W powyższym przykładzie metoda upTo: zwraca ciąg znaków ‘Ala’ (bez spacji), a następnie wywołana metoda next zwraca znak $m, ponieważ wskaznik został przez metodę upTo: przesunięty za spację.

Jeżeli żądany obiekt nie zostanie znaleziony, to metoda upTo: zwraca całą pozostałą zawartość strumienia, a wskaznik zostaje ustawiony na jego końcu.

upToEnd

Metoda upToEnd zwraca zawartość strumienia od aktualnej pozycji wskaznika odczytu do końca strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream upTo: Character space.
stream upToEnd.

W powyższym przykładzie metoda upTo: ustawia wskaznik odczytu za pierwszą spacją, a metoda upToEnd zwraca ciąg znaków ‘ma kota’.

upToAndSkipThroughAll:

Metoda upToAndSkipThroughAll: zwraca zawartość strumienia od aktualnej pozycji wskaznika odczytu do pierwszego wystąpienia kolekcji będącej argumentem tej metody, ale bez tej kolekcji. Następnie wskaznik odczytu zostaje ustawiony za ostatnim elementem tej kolekcji w strumieniu. Jeżeli żądana kolekcja nie zostanie znaleziona, metoda upToAndSkipThroughAll: zwraca całą zawartość strumienia od aktualnej pozycji wskażnika do jego końca, a wskaznik zostaje ustawiony na końcu strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream upToAndSkipThroughAll: 'kot'.
stream next.

W powyższym przykładzie metoda upToAndSkipThroughAll: zwróci ciąg znaków ‘Ala ma ’, a następująca po niej metoda next zwróci znak $a.

stream := ReadStream on: 'Ala ma kota'.
stream upToAndSkipThroughAll: 'Tomek'.
stream atEnd.

W tym przykładzie metoda upToAndSkipThroughAll: zwróci ciąg znaków ‘Ala ma kota’, a następująca po niej metoda atEnd zwróci wartość true (tzn. wskaznik odczytu znajduje się na końcu strumienia).

Zapis do strumienia

nextPut:

Metoda nextPut: wstawia obiekt będący jej argumentem do strumienia, pod aktualną pozycją wskaznika zapisu i zwraca jako wynik ten obiekt.

stream := WriteStream on: String new.
stream nextPut: $x.
stream contents.

W powyższym przykładzie znak $x jest wstawiany na początku strumienia. Metoda contents zwraca kolekcję ‘x’.

nextPutAll:

Metoda nextPutAll: wstawia kolekcję będącą jej argumentem do strumienia, pod aktualną pozycją wskaznika zapisu i zwraca jako wynik tę kolekcję.

stream := WriteStream on: String new.
stream nextPutAll: 'Witaj'.
stream contents.

W powyższym przykładzie kolekcja ‘Witaj’ jest wstawiana na początku strumienia. Metoda contents zwraca następnie zawartość strumienia, czyli ciąg znaków ‘Witaj’.

print:

Metoda print: wstawia do strumienia wynik metody printString zdefiniowanej w obiekcie będącym jej argumentem. W przypadku gdy metoda ta nie jest w danym obiekcie zaimplementowana, zostanie użyta metoda printString zdefiniowana w nadklasie Object.

stream := WriteStream on: String new.
stream
	print: OrderedCollection new;
	print: 725.
stream contents.

W powyższym przykładzie metoda print: wstawi do strumienia najpierw ciąg znaków ‘OrderedCollection ()‘, a następnie ‘725’. Metoda contents zwróci nam ciąg znaków ‘OrderedCollection ()725’.

Zmiana pozycji wskaznika

Po utworzeniu strumienia wskaznik pozycji znajduje się na jego początku (wskazuje pierwszy element strumienia – pozycja 0). Odczyt ze strumienia lub zapis do niego przesuwają odpowiednio ten wskażnik.

position

Metoda position zwraca aktualną pozycję wskaznika.

stream := ReadStream on: 'Ala ma kota'.
stream next.
stream next.
stream position.

W powyższym przykładzie metoda position zwróci liczbę 2.

position:

Metoda position: ustawia aktualny wskaznik zapisu lub odczytu na pozycję oznaczoną liczbą będącą argumentem tej metody. Jeżeli liczba ta będzie większa niż rozmiar strumienia, to wystąpi błąd.

stream := ReadStream on: 'Ala ma kota'.
stream position: 4.
stream next.

W powyższym przykładzie wskaznik zostanie ustawiony za pierwszą spacją, a następnie wywołana metoda next zwróci znak $m.

stream := ReadStream on: 'Ala ma kota'.
stream position: stream size - 1.
stream next.

W tym przykładzie wskaznik zostanie ustawiony na pozycji 10 (rozmiar strumienia minus jeden), a metoda next zwróci znak $a.

reset

Metoda reset ustawia wskaznik aktualnej pozycji odczytu lub zapisu na początku strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream
	next;
	next;
	next;
	reset;
	next.

W powyższym przykładzie pierwsze trzy odczyty przy pomocy metody next przesuną wskaznik na pozycję 3 (przed znak spacji po słowie Ala), metoda reset cofnie wskaznik na pozycję 0, a kolejne wywołanie metody next zwróci znak $A.

setToEnd

Metoda setToEnd działa podobnie do metody reset, z tym że przesuwa wskaznik aktualnej pozycji odczytu lub zapisu na koniec strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream
	position;
	setToEnd;
	position.

W powyższym przykładzie pierwsze wywołanie metody position zwróci liczbę 0 (początek strumienia), setToEnd przesunie wskaznik na koniec strumienia, a kolejne wywołanie metody position zwróci liczbę 11.

skip:

Metoda skip: przesuwa wskaznik odczytu lub zapisu o liczbę będącą jej argumentem. Liczba ta może być również ujemna.

stream := ReadStream on: 'Ala ma kota'.
stream
	skip: 4;
	next.

W powyższym przykładzie metoda skip: przesuwa wskaznik odczytu o 4 pozycje do przodu (przed słowo ”ma”). Następnie wywołana metoda next zwraca znak $m.

skipThrough:

Metoda skipThrough: przesuwa wskaznik odczytu lub zapisu za pierwsze wystąpienie obiektu będącego jej argumentem i zwraca swój strumień. Jeżeli żądany obiekt nie zostanie znaleziony, to zwracana jest wartość nil, a wskaznik jest ustawiany na koniec strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipThrough: $k;
	next.

W powyższym przykładzie metoda skipThrough: przesuwa wskaznik odczytu za znak $k w słowie „kot”. Następnie wywołana metoda next zwraca znak $o.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipThrough: $x;
	next

W tym przykładzie metoda skipThrough: przesuwa wskaznik odczytu na koniec strumienia (ponieważ znak $x w nim nie występuje), a metoda next zwraca wartość nil.

skipThroughAll:

Metoda skipThroughAll: przesuwa wskaznik odczytu lub zapisu za pierwsze wystąpienie kolekcji będącej jej argumentem i zwraca swój strumień. Jeżeli żądana kolekcja nie zostanie znaleziona, to zwracana jest wartość nil, a wskaznik jest ustawiany na koniec strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipThroughAll: ‘ma ko’;
	next.

W powyższym przykładzie metoda skipThroughAll: przesuwa wskaznik odczytu za kolekcję ‘ma ko’. Następnie wywołana metoda next zwraca znak $t.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipThroughAll: ‘Tomek’;
	next.

W tym przykładzie metoda skipThroughAll: przesuwa wskaznik odczytu na koniec strumienia (ponieważ kolekcja ‘Tomek’ w nim nie występuje), a metoda next zwraca wartość nil.

skipUpTo:

Metoda skipUpTo: przesuwa wskaznik odczytu lub zapisu przed pierwsze wystąpienie obiektu będącego jej argumentem.. Jeżeli żądany obekt nie zostanie znaleziony, to zwracana jest wartość nil, a wskaznik jest ustawiany na koniec strumienia.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipUpTo: $m;
	next.

W powyższym przykładzie metoda skipUpTo: przesuwa wskaznik odczytu do znaku $m. Następnie wywołana metoda next zwraca ten znak.

stream := ReadStream on: 'Ala ma kota'.
stream
	skipUpTo: $x;
	next.

W tym przykładzie metoda skipUpTo: przesuwa wskaznik odczytu na koniec strumienia (ponieważ znak $x w nim nie występuje), a metoda next zwraca wartość nil.

Zamykanie strumieni

close

Strumienie wewnętrzne nie muszą być zamykane. Strumienie zewnętrzne należy zamykać wysyłając do nich metodę close.

commit

Metoda commit zapisuje zawartość bufora do strumienia zewnętrznego (np.pliku) Powinna być wysłana do takiego strumienia przed jego zamknięciem, jeżeli wcześniej byly w nim zapisywane jakieś informacje.

Strumienie zewnętrzne

Strumienie zewnętrzne zapewniają dostęp do zewnętrznych strumieni danych takich jak pliki, bazy danych czy połączenia sieciowe. Podstawowe operacje są tutaj takie same jak w przypadku strumieni wewnętrznych, niektóre metody różnią się jednak zasadniczo.

Tworzenie strumieni zewnętrznych

Strumienie zewnętrzne są tworzone przez wysłanie do obiektu reprezentującego dany typ danych jednej z następujących metod: readStream, writeStream, appendStream, readWriteStream, czy readAppendStream.

Poniżej przdstawiony jest przykład dodania do pliku tekstowego ‘wierszyk.txt’ w nowej linii zdania ‘Ala ma kota.’.

file := ‘wierszyk.txt’ asFilename.
stream := file appendStream.
stream cr; nextPutAll: ‘Ala ma kota‘.
stream commit.

Metoda commit została na końcu użyta w celu zapisu do pliku bufora w systemie operacyjnym. W przypadku zamknięcia dostępu do pliku metodą close nie trzeba używać commit, bufor jest opróżniany automatycznie.

W przypadku otwierania istniejącego pliku jako strumienia do zapisu, jego zawartość zostanie nadpisana natychmiast po otwarciu, a jego rozmiar zostanie ustawiony na 0.

file := ‘readme.txt’ asFilename.
stream := file writeStream.

Dzieje się tak, ponieważ po otwarciu pliku metodą writeStream wskaznik pozycji zapisu znajduje się na początku pliku. W celu dopisania czegoś do już istniejącego pliku należy użyć metodę appendStream.

Standardowo kolekcje zewnętrzne są otwierane w trybie tekstowym. W celu ustawienia trybu binarnego do strumienia nalezy wysłać polecenie binary.

file := ‘program.exe’ asFilename.
stream := file readStream binary.

Zapis i odczyt strumieni zewnętrznych

Do zapisu i odczytu strumieni zewnętrznych używa się tych samych metod co w przypadku strumieni wewnętrznych, tzn, next:, nextPut: itd. Przy odczycie należy sprawdzać, czy nie został już osiągnięty koniec danego strumienia.

Poniżej przedstawiony został przykład kopiowania zawartości pliku tekstowego ‘zrodlo.txt’ do nowego pliku o nazwie ‘nowy.txt’.

readStream := ‘zrodlo.txt’ asFilename readStream.
writeStream := ‘nowy.txt’ asFilename writeStream.
[readStream atEnd] whileFalse:[ | char |
	char := readStream next.
	writeStream nextPut: char].

Przesuwanie wskaznika aktualnej pozycji odczytu lub zapisu (metoda position:) nie jest możliwe dla strumieni tylko do zapisu, ponieważ do jego przesunięcia wymagana jest funkcjonalność odczytu.Aby przesunąć wskaznik podczas zapisu należy uzyć strumienia do odczytu i zapisu.

Przemysław Nieściór, 19.02.2016

What's new

  • Deploying Pier on Ubuntu with Plesk at the german provider 1blu
    28 February 201312:21:04 pm by Przemysław Nieściór
    This tutorial describes how to deploy Pier on an Ubuntu Linux distribution with Plesk at the german provider 1blu. It assumes that you want to install a pier image on an Ubuntu Linux with Apache 2 und...
  • Mechanizm switch-case w Smalltalku
    11 June 201212:00:43 pm by Przemysław Nieściór
    ENGLISH VERSION BELOW POLISH VERSION Język Smalltalk nie oferuje wraz ze swoimi standardowymi klasami odpowiednika mechanizmu switch-case, popularnego na przykład w językach wywodzących sie z języka...