Strumienie
W tej lekcji zajmiemy się strumieniami. Określenie strumień oznacza powiązanie pomiedzy kilkoma urządzeniami. Strumień służy do przesyłania danych z jednego urządzenia do drugiego. Raz jest to pamięć i dysk, kiedy to zapisujemy plik na dysk. Innym razem pamięć i drukarka podczas drukowania. Takich powiązań może być wiele. O niektórych z nich pogadamy w tej lekcji. Chciałem jeszcze tylko powiedzieć, że strumienie nie są integralną częścią samego języka. Bowiem C++ sam w sobie nie posiada instrukcji umożliwiających komunikację z urządzeniach wejściowymi, bądź wyjściowymi. Jeżeli chcesz pobazgrolić trochę po ekranie lub odczytać informacje z klawiatury musisz skorzystać z funkcji bibliotecznych lub samemu je sobie napisać

Ten drugi sposób jest cięższy w realizacji, ale ma swoje zalety. Funkcje napisane w konkretnym celu działają zazwyczaj lepiej i szybciej. Jednakże nie jest to takie trywialne. Trzeba bowiem znać język maszynowy, czyli assemblera. Jeżeli umiesz się posługiwać assemblerem to na pewno ucieszysz się, że C++ zezwala na umieszczanie wstawek asemblerowych bezpośrednio w kodzie C++! Wystarczy skorzystać ze słowa kluczowego asm i w klamerkach umieścić instrukcje w asm'ie. Dla wtajemniczonych mały przykład:
asm
{
//instrukcje w asemblerze
}
Taki zapis spotkałem wielokrotnie w literaturze. Jednak niektórzy twierdzą, że on nie zadziała. Tak więc jeśli coś pójdzie źle to spróbuj zapisać tak:
asm{
//instrukcje w asemblerze
}
niektóre kompilatory nie akceptują żadnej z tych składni. Wówczas spróbuj napisać w taki sposób:
asm ("instrukcja"

;
Jeszcze jedno. Nie wszystkie kompilatory C++ posiadają wbudowany kompilator asemblera. Wtedy trzeba kompilator asm'a umieścić w folderze, w którym mieszczą się takie pomocnicze programiki. Ja korzystam ze środowiska programistycznego Dev C++, który zawiera kompilator asm'a. Tobie także polecam to środowisko. Wracając do strumieni. Aby skorzystać ze strumienia należy wykonać kilka rzeczy opisanych poniżej.
otworzenie strumienia - zdefiniowanie
określenie, przepływu danych - utworzenie powiązania między urządzeniami
dokonanie operacji na strumieniu - skorzystanie ze strumienia
zamknięcie strumienia - odwołanie
Myslę, że Cię nie przeraziłem powyżdzą wyliczanką

Wydaje się to bardzo skomplikowane i trudne, ale zaręczem iż tak nie jest. Korzystanie ze strumieni jest łatwe i przyjemne. Dodatkowo istnieją strumienie predefiniowane, czyli definiowane przez kompilator automatycznie i wcale nie musisz uczyć się na pamięć powyższej litani

Teraz właśnie pogadamy o tych predefiniowanych strumieniach. Warto tutaj jeszcze pamietać, iż strumienie są to obiekty konkretnych klas. Klasy te są zdeklarowane w plikach nagłówkowych iostream.h i fstream.h.
strumień wejściowy - cin
Jest to podstawowy strumień wejściowy C++. Jego działanie polega na odczytaniu ciągu znaków wpisanych z klawiatury. Strumień cin jest obiektem klasy istream. Jej deklaracja znajduje się w pliku iostream.h. Aby wstawić do zmiennej liczbowej wartość z klawiatury należy napisać tak:
long zmienna;
cin >> zmienna;
Już same strzałki sugerują wykonywaną akcję. Instrukcja: cin >> zmienna; oznacza przelanie zawartości strumienia cin do zmiennej. Pytanie tylko, co się w takim strumieniu znajduje? A no wszystko to, co wstukaliśmy z klawiatury. Po wykonaniu tego fragmentu kodu na ekranie ukarze się migający kursor. Umożliwia on umieszczenie w strumieniu dowolnych danych. Tylko uważaj! Strumień przyjmuje wszystkie znaki. W naszym przykładzie chcemy wstawić zawartość strumienia do zmiennej typu long. Co zatem stanie się gdy wpiszemy litery? No cóż.. raczej jest to błąd. Bynajmniej kompilator nie potrafi na takie sytuacje zareagować. Po prostu jeżeli dane będą nie właściwe to zmienna nie zostanie zmodyfikowana. Należy więc uważać i podawać właściwe dane. Oprócz tego ostatecznym zakończeniem wpisywania znaków z klawiatury jest znak entera, co nie zawsze jest odpowiednie.
strumień wyjściowy - cout
Pewnie już się domyślasz, do czego służy ten strumień. Krótko mówiąc służy do przelania wartości zapisanej w konkretnej zmiennej na ekran. Strumień cout to obiekt klasy ostream. Jej deklaracja umieszczona została w pliku nagłówkowym iostream.h. Składniowo też jest prosto. Wystarczy zapisać tak:
double zmienna = 345.343;
cout > znak;].
istream& get (char *bufor, int ilosc, int ogranicznik = '\n'

;
Podobnie, jak poprzednio funkcja get(char *, int, int) służy do pobrania informacji ze strumienia. Poprzednio był to jeden bajt. Tym razem możemy dodatkowo określić ilość pobranych bajtów. Pierwszy argument to wskaźnik do tablicy znakowej, w której będą umieszczane pobierane bajty. Argument drugi to ilość wczytanych bajtów. Trzeci argument jest domniemany i określa, po którym znaku należy zakończyć pobieranie danych. W domyśle jest to znak końca wiersza. Znak kończący nie jest wczytywany.
istream& getline (char *bufor, int ilosc, int ogranicznik = '\n'

;
Działanie tej funkcje jest bardzo zbliżone do poprzedniej. Różnica polega na tym, że znak ograniczający również zostanie pobrany ze strumienia.
istream& read (char *bufor, int ilosc);
Kolejna przydatna funkcja. Służy do odczytu ze strumienia dowolnej ilości bajtów. Odczytuje dane w postaci binarnej. Pierwszy argument to oczywiście adres bufora, do którego powędruja wczytywane dane. Kolejny to ilość wczytywanych bajtów.
istream& ignore (int ilosc = 1, int ogranicznik = EOF);
Następna dość ciekawa funkcja. Jej działanie skupia się na przeskoczeniu kilku bajtów. Jest to przydatne w sytuacjach, gdy chcemy pominąć pewne dane. Argument pierwszy to ilość pomijanych bajtów. Drugi argument to znak ograniczający. W domyśle jest to znak końca pliku, czyli EOF.
int gcount ();
Informuje, ile bajtów zostało wczytanych podczas ostatniej operacji odczytu ze strumienia.
int peek ();
Ta funkcja służy do sprawdzenia, co też znajduje się w strumieniu. Sama funkcja nie pobiera bajtu, a jedynie informuje o jego wartości.
istream& putback (char znak);
Funkcja służy do zwrócenia do strumienia znaku, który został już pobrany wcześniej.
ostream put (char znak);
Ta funkcja wstawia do strumienia jeden bajt.
ostream write (const char *bufor, int ilosc);
Funkcja wstawia do strumienia, na którym pracuje określoną ilość znaków zawartych w tablicy. Pierwszy argument to właśnie ta tablica źródłowa, a drugi do ilość wstawianych bajtów.
streampos tellg ();
Funkcja tellg() informuje, gdzie aktualnie znajduje się wskaźnik czytania. Ten tajemniczy typ streampos zo zwykły typ long.
streampos tellp ();
Jak nie trudno się domyślić, funkcja tellp() zwraca pozycję wskaźnika pisania.
istream& seekg (streampos, seek_dir = ios::beg);
Ta funkcja służy do określenia nowego położenia wskaźnika czytania. Argument pierwszy to typ streampos, czyli po prostu long, zaś drugi to typ wyliczeniowy enum. Za jego pomocą okrelamy położenie wskaźnika w strumieniu. Jeśli chcemy przesunąć wskaźnik czytania względem bieżšcej pozycji to podajemy w drugim argumencie ios::cur. Jeżeli chcesz ustawić pozycję wskaźnika zaczynając od początku strumienia należy napisać: ios::beg, jako argument drugi. Natomiast jeśli chciałbyś przeskoczyć do określonego bajtu numerując od końca strumienia trzeba podać: ios::end w drugim argumencie.
ostream& seekp (streampos, seek_dir = ios::beg);
Jej działanie również polega na pozycjonowaniu wskaźnika. Tym razem jest to wskaźnik pisania. Obowiązują tutaj takie same zasady, jak w funkcji poprzedniej.
int good ();
Bardzo przydatna funkcja informująca, czy ostatnia operacja na strumieniu powiodła się. W przypadku sukcesu funkcja zwraca wartość niezerową. W razie porażki rezultatem jest zero.
int eof ();
Również funkcja informacyjna. Tym razem zwrócona zostanie wartość zerowa w sytuacji, gdy został przekroczony zakres strumienia. Przeważnie stosowana jest do skontrolowania długości pliku.
int fail ();
Rezultatem tej funkcji jest wartość niezerowa, w przypadku gdy wystąpił jakiś błąd podczas pracy ze strumieniem.
int bad ();
Ta funkcja również zwraca wartość niezerową, jeżeli zostanie napotkany błąd ze strumieniem. Dotyczy poważniejszych błędów.
Na tym zakończę ten rozdział. Oczywiście funkcji składowych do operacji za strumieniami jest więcej. Ja przedstawiłem jedynie część z nich. Tak naprawdę sam korzystam z nich sporadycznie! Wolę funkcje, jakie oferuje mi Windows. O tych funkcjach na razie nie mówiłem. Postaram się za jakiś czas dodać kilka lekcji opisujących tworzenie programów pod Win. Wtedy nadmienię także o funkcjach zapisu i odczytu z dysku. Póki co pobaw się trochę tym, co jest