beesoft.org

STL. Strumienie wejscia/wyjscia.

Klasy wejscia/wyjscia nazywane sa biblioteka IOStream.
Jest ona oczywiscie czescia, i to bardzo istotna, biblioteki STL.
Jest ona jedyna czescia biblioteki STL, ktora juz istniala zanim powstala STL.
Biblioteka operacji wejscia/wyjscia byla wczesniej stworzona przez firme AT&T.
Po dokoniu pewnych zmian, zostala zaadoptowana jako czesc skladowa biblioteki standardowej.

W jezyku C++ operacje wejscia/wyjscia wykonywane przy uzyciu strumieni.
Strumien to po prostu obiekt, ktorego wlasnosci okreslone sa przez jego klase. Juz sama nazwa 'strumien' sugeruje obrazowe wyobrazenie tych operacji. Cos do strumienia wplywa, i cos z niego wyplywa. Cos wysylamy na jego wejscie, i cos dostajemy na jego wyjsciu.

Omowie nastepujace tematy:

Klasy strumieni
Globalne, predefiniowane obiekty strumieni
Operatory strumieniowe
Operatory wyjscia typow wbudowanych
Operatory wejscia typow wbudowanych
Stan strumienia
Operatory strumieniowe w wyrazeniach logicznych
Nieformatujace funkcje odczytu danych

Klasy strumieni.

Klasy wejscia/wyjscia sa na tyle uniwersalne, ze moga dotyczyc roznych urzadzen czy klas. My skoncentrujemy sie na wejsciu z klawiatury i wyjsciu na ekran.

Klasa wejsciowa istream definiuje strumienie, sluzace do odczytu danych (#include <istream>).
Klasa dziedziczy klase podstawowa basic_istream.

Klasa wyjsciowa ostream definiuje strumienie, sluzace do zapisu danych (#include <ostream>).
Klasa dziedziczy klase podstawowa basic_ostream.

Obu klas mozna uzywać osobno, ale nie jest to zbyt wygodne. Dlatego tez istnieje klasa iostream (#include <iostream>), ktora dziedziczy obie klasy, udostepniajac nam funkcjonalnosc jednej i drugiej.
Tak wiec dokonujac w swoim programie obu rodzajow operacji wystarczy na poczatku wlaczyc tylko iostream.


Globalne, predefiniowane obiekty strumieni.

cin
Obiekt 'cin' (klasy istream) jest strumieniem wejsciowym, uzywanym do oczytu danych wprowadzanych przez uzytkownika. Normalnie obiekt zwiazany jest z klawiatura.
cout
Obiekt 'cout' (klasy ostream) jest strumieniem wyjsciowym, uzywanym do wypisywania danych wyprowadzanych przez program. Normalnie obiekt zwiazany jest z ekranem monitora.
cerr
Obiekt 'cerr' (klasy ostream) jest strumieniem wyjsciowym, uzywanym do wypisywania informacji o bledach. Normalnie obiekt zwiazany jest z ekranem monitora.
Uwaga:
Dosc czesto programisci zastanawiaja sie po co dwa strumienie, ktore wypisuja swoje dane na ekran.
Sprawa jest dosys prosta. Kazdy ze strumieni mozna przekierowac na inne urzadzenie.
Ale bardziej istotne jest przechwytywanie strumieni. Od poczatkow swojego istnienia Unix skladal sie, jak z cegielek, z malych silnych i uzytecznych programow. Wiele innych programow wykorzystuje je do swoich wlasnych celow. Przechwycenie strumieni pozwala rozrozniac komunikaty o bledach od zwyklej informacji. Np. moj program 'Cobras' bedacy srodowiskiem sluzacym do pisania programow, wykorzystuje program 'make'. Przed jego uruchomieniem ustawia przechwytywanie strumieni. Informacje o kompilowanych wlasnie plikach sa przechwytywane z 'cin' i sa wyswietlane w oknie infomujacym o przebiegu procesu. Natomiast komunikaty o bledach sa przechwytywane z 'cerr' i bez zbednych rozwazan wiadomo, ze cos bylo nie tak. I te informacje wyswietlane sa w osobnym, specjalnym oknie. Taki to pozytek z istnienia dwoch strumieni wyjsciowych.

Operatory strumieniowe.

<<
Operator wyjscia, zapisu do strumienia. Np. cout <<.
>>
Operator wejscia, odczytu ze strumienia. Np. cin >>.
Na przyklad:
#include <iostream>
#include <string>
using namespace std;

int main()
{
    int value;
    string name = "Bolek";

    cout << 5;
    cout << name;

    cout << "Podaj liczbe: ";
    cin >> value;
    cout << "Masz " << value << " zl";

    return 0;
}
Program ten dziala jak najbardziej prawidlowo. Niestety nie wyglada to na ekranie zbyt dobrze. Wszystkie operacje << wypisuja kolejne informacje jak leci, jedna za druga. Malo czytelne. Wyjsciem jest pisanie kolejnych danych w osobnych liniach. W tym celu wymyslono manipulator o nazwie endl (end of line), ktory po wyslaniu do strumienia symbolizuje rzadanie przejscia do nastepnej linii. Czyli program powinien wygladac tak:
#include <iostream>
#include <string>
using namespace std;

int main()
{
    int value;
    string name = "Bolek";

    cout << 5 << endl;
    cout << name << endl;

    cout << "Podaj liczbe: ";
    cin >> value;
    cout << "Masz " << value << " zl" << endl;

    return 0;
}
Zamiast endl do strumienia mozna przeslac znane z C "\n". Efekt bedzie taki sam.
W powyzszym przykladzie nalezy zauwazyc dwie rzeczy.

Operatory wyjscia typow wbudowanych.

Klasa ostream ma tak zdefiniowany operator <<, aby obslugiwala typy tzw. wbudowane.
Predefinowane sa nastepujace operacje wyjscia:

basic_ostream& operator<<( short n );
basic_ostream& operator<<( int n );
basic_ostream& operator<<( long n );

basic_ostream& operator<<( unsigned short u );
basic_ostream& operator<<( unsigned int u );
basic_ostream& operator<<( unsigned long u );

basic_ostream& operator<<( float f );
basic_ostream& operator<<( double f );
basic_ostream& operator<<( long double f );

basic_ostream& operator<<( bool n );
basic_ostream& operator<<( const void* p );

basic_ostream& put( char c );
basic_ostream& write( const char* p, streamsize n );

Wyslanie do strumienia wskaznika 'void*' nie spowoduje wyprowadzenie na ekran zawartosci przez niego wskazywanej, ale wartosc jego adresu.

Wartosci logiczne (typu bool) false i true, sa wyswietlane na ekranie jako 0 i 1.
Jesli chcesz na ekranie otrzymać wartosci w postaci napisow, musisz zastosować flage formatujaca boolalpha.
Sprawdzmy to uruchamiajac nastepujacy program:


#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	cout << true << ' ' << false << endl;
	cout << boolalpha;
	cout << true << ' ' << false << endl;
}
W pierwszej linii zostana wyswietlone liczby: 1 0.
W drugiej linii zobaczymy jednak slowa: true false.

Operatory wejscia typow wbudowanych.

Klasa istream ma tak zdefiniowany operator >>, aby obslugiwala typy tzw. wbudowane.
Predefinowane sa nastepujace operacje wejsciowe:

basic_istream& operator>>( short& n );
basic_istream& operator>>( int& n );
basic_istream& operator>>( long& n );

basic_istream& operator>>( unsigned short& u );
basic_istream& operator>>( unsigned int& u );
basic_istream& operator>>( unsigned long& u );

basic_istream& operator>>( float& f );
basic_istream& operator>>( double& f );
basic_istream& operator>>( long double& f );

basic_istream& operator>>( bool& n );
basic_istream& operator>>( void*& n );

Stan strumienia.

W celach diagnostycznych dostepne sa tzw. znaczniki stanu strumienia.
Pozwalaja one okreslic czy strumien napotkal jakies problemy, czy nadaje sie do dalszej pracy czy tez nalezy podjac jakies specjalne dzialanie.
Znaczniki sa typu iostate, stanowiacego skladowa klasy ios_base. Jaki to jest konkretnie typ (czy typ wyliczeniowy, czy typ calkowity, czy egzemplarz klasy bitset) nie jest okreslone przez standard C++. Zalezy on od konkretnej implementacji biblioteki STL.

Znacznik Znaczenie
goodbit Operacja wykonana poprawnie.
eofbit Zostal napotkany znacznik konca pliku.
failbitt Blad: operacja zakonczyla sie niepowodzeniem.
badbit Blad krytyczny: strumien w obecnym stanie nie nadaje sie do dalszej pracy.

Tak naprawde znaczniki istotna role graja przy pracy ze strumieniami zwiazanymi z plikami.
Aby uzytkownik nie musial badac poszczegolnych znacznikow (bitow), udostepniono funkcje, ktore informuje o stanie konkretnych znacznikow.

Funkcja skladowa Znaczenie
bool good() const; Zwraca true jesli wszystko jest w porzadku (goodbit).
bool eof() const; Zwraca true gdy napotkana znak konca pliku (eofbit).
bool fail() const; Zwraca true gdy wystapil blad (failbit lub badbit).
bool bad() const; Zwraca true gdy wystapil blad krytyczny (badbit).
iostate rdstate() const; Zwraca aktualny stan wszystkich znacznikow.
void clear( iostate f = goodbit ) const; Zeruje wszystkie znaczniki i nadaje im zadana wartosc.
Domyslnie zeruje wszystkie znaczniki.
void setstate( iostate f ) const; Ustawia wartosc konkretnego znacznika.

Operatory strumieniowe w wyrazeniach logicznych.

Czesto operacje wejscia/wyjscia odbywaja sie w petlach, np. while. Oczywiscie w kolejnych wykonaniach petli stan strumienia powinien byc poprawny. I my powinnismy to sprawdzac i odpowiednio reagowac na zmiany zachodzace w strumieniu. Mozna by sprawdzac to poprzez kontrole stosownych znacznikow stanu. Jednak standard C++ ulatwil nam zycie. Wprowadzono dwa operatory, które robia to za nas.

Operator Znaczenie
operator void* () Zwraca wartosc, okreslajaca czy ze strumieniem wszystko jest OK.
operator ! () Zwraca wartosc, okreslajaca czy wystapil blad.

Ponizej kilka przykladow uzycia:


while( cin ) {	// rob swoje dopoki stan strumienia wejsciowego jest poprawny.
...
}

if( !cin ) {	// strumien jest w stanie bledu
...
}

if( cin >> zmienna ) {
	// odczyt powiodl sie, wykorzystaj to
...
}

if( !( cin >> zmienna )) {
	// nie udalo sie, tutaj mozesz zaregowac na powstala sytuacje
...
}

Nieformatujace funkcje odczytu danych istream.

Funkcja Opis
int get ()
Funkcja odczytuje ze strumienia jeden znak.
Jezeli odczyt sie powiodl funkcja zwraca znak. W przeciwnym razie funkcja wywoluje setstat( failbit ), a nastepnie zwraca EOF.
istream& get ( char& c )
istream& get ( unsigned char& c )
istream& get ( signed char& c )
Funkcja odczytuje jeden znak i zapisuje w miejsce wskazane przez 'c'.
Jezeli odczyt sie nie powiodl wywolywana jest funkcja setstate( failbit ).
istream& get ( streambuf& sb, char marker ='\n' )
Odczytuje kolejne znaki ze strumienia i zapamietuje je w buforze kontrolowanym przez 'sb'.
Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. napotkano koniec pliku,
  2. wystapil blad podczas przekazania znaku do 'sb',
  3. natrafiono znak 'marker',
    znak ten pozostaje w strumieniu,
  4. zostanie zgloszony wyjatek.
Jesli nie odczytano zadnego znaku, wywolywana jest funkcja setstate( failbit ).
istream& get ( char* buffer, int count )
istream& get ( unsigned char* buffer, int count )
istream& get ( signed char* buffer, int count )
Odczytuje kolejne znaki ze strumienia i zapamietuje je w wskazanym buforze. Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. odczytano juz (count - 1) znakow,
  2. napotkano koniec pliku,
    wywolywana jest funkcja setstate( eofbit ),
  3. napotkano znak nowej linii ('\n')
    znak ten pozostaje w strumieniu.
Jesli nie odczytano zadnego znaku, wywolywana jest funkcja setstate( failbit ).
istream& get ( char* buffer, int count, char marker )
istream& get ( unsigned char* buffer, int count, char marker )
istream& get ( signed char* buffer, int count, char marker )
Odczytuje kolejne znaki ze strumienia i zapamietuje je w wskazanym buforze. Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. odczytano juz (count - 1) znakow,
  2. napotkano koniec pliku,
    wywolywana jest funkcja setstate( eofbit ),
  3. napotkano znak 'marker',
    znak ten pozostaje w strumieniu.
Jesli nie odczytano zadnego znaku, wywolywana jest funkcja setstate( failbit ).
istream& getline ( char* buffer, int count )
istream& getline ( unsigned char* buffer, int count )
istream& getline ( signed char* buffer, int count )
Odczytuje kolejne znaki ze strumienia i zapamietuje je w wskazanym buforze. Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. odczytano juz (count - 1) znakow,
  2. napotkano koniec pliku,
    wywolywana jest funkcja setstate( eofbit ),
  3. napotkano znak nowej linii ('\n')
    znak ten zostanie pobrany ze strumienia, ale nie zapamietany w buforze..
Jesli nie odczytano zadnego znaku, wywolywana jest funkcja setstate( failbit ).
istream& getline ( char* buffer, int count, char marker )
istream& getline ( unsigned char* buffer, int count, char marker )
istream& getline ( signed char* buffer, int count, char marker )
Odczytuje kolejne znaki ze strumienia i zapamietuje je w wskazanym buforze. Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. odczytano juz (count - 1) znakow,
  2. napotkano koniec pliku,
    wywolywana jest funkcja setstate( eofbit ),
  3. napotkano znak 'marker',
    znak ten zostanie pobrany ze strumienia, ale nie zapamietany w buforze..
Jesli nie odczytano zadnego znaku, wywolywana jest funkcja setstate( failbit ).
istream& ignore ( int n = 1, int marker = EOF ) Funkcja odczytuje ze strumienia ciag znakow, bez ich zapamietywania.
Znaki sa pobierane, dopoki nie wystapi jeden z nastepujacych przypadkow:
  • pobrano juz n znakow,
  • napotkano koniec pliku,
    wywolywana jest funkcja setstate( eofbit ),
  • napotkano znak 'marker', znak zostanie pobrany ze strumienia.
    Sytuacja ta nie wystapi nigdy jezeli 'marker' ma wartosc EOF.
istream& read ( buffer, count ) Odczytuje kolejne znaki ze strumienia i zapamietuje w buforze. Funkcja odczytuje kolejne znaki, dopoki nie wystapi jeden z nastepujacych warunkow:
  1. odczytano juz count znakow,
  2. napotkano koniec pliku,wywolywana jest funckja
    setstate( eofbit ),
int peek () Funkcja "probnik". Odczytuje nastepny znak ze strumienia, ale znak w strumieniu pozostaje. Znak ten jest nadal dostepny dla funkcji czytajacych ze strumienia.
istream& unget ()
istream& putback ( char c )
Obie funkcje moga zwrocic do strumienia ostatni odczytany z tego strumienia znak. UWAGA: postac funkcji putback moze sugerowac, ze mozna 'wlozyc' do strumienia dowolny znak. Ale tak nie jest!!! Mozna 'cofnac' do strumienia faktycznie ostatnio odczytany z niego znak.
Nalezy pamietac, ze taki zwrot nie zawsze moze byc mozliwy. W przypadku niepowodzenia operacji wywolywana jest funkcja setstate( badbit ). Nie mozna kilka razy pod rzad cofac do strumienia kolejnych, ostatnio odczytanych znakow. Standard gwarantuje jedynie jedno wywolanie pomiedzy dwoma operacjami odczytu.
int gcount () const
Funkcja zwraca liczbe odczytanych ze strumienia znakow. Odczytanych przez ostatnia nieformatujaca funkcje odczytu.

Powrot na poczatek strony.

Contact: piotr@beesoft.org
(C) 2006-2008 beesoft.org
Last modification date: 2008-06-29
Visitis counter:
counter of visits