Strumienie wejścia i wyjścia

Biblioteka strumieni wejścia i wyjścia pozwala na pobieranie i wysyłanie sformatowanych i niesformatowanych zbuforowanych tekstów i wartości liczbowych. Definicje narzędzi związanych ze strumieniami wejścia i wyjścia znajdują się w nagłówkach <istream>, <ostream>, itp.

Strumień ostream konwertuje mające typy obiekty na strumienie znaków (bajtów).

Strumień istream konwertuje strumienie znaków (bajtów) na obiekty o określonych typach.

Strumień iostream może służyć zarówno jako istream, jak i ostream. Widoczne na schematach bufory to „bufory strumieniowe” (streambuf).

Istnieją trzy standardowe strumienie wejścia i wyjścia:

  1. cout - standardowy strumień wyjściowy znaków (często domyślnie jest nim ekran),

  2. cin - standardowy strumień wejściowy znaków (często domyślnie jest nim klawiatura),

  3. cerr - standardowy strumień wyjściowy błędów (nie ma bufora).

Hierarchia strumieni wejścia i wyjścia

Strumień istream można połączyć w urządzeniem wejściowym (np. klawiaturą), plikiem lub łańcuchem. Analogicznie strumień ostream można połączyć z urządzeniem wyjściowym (np. oknem tekstowym), plikiem lub łańcuchem.

Strumień można otworzyć za pomocą konstruktora lub wywołując funkcję open():

Typy strumieniowe

stringstream(m)

Tworzy pusty strumień z ustawionym trybem m

stringstream(s,m)

Tworzy strumień łańcuchowy zawierający łańcuch s w trybie m

fstream()

Tworzy strumień plikowy do otwarcia później

fstream(s,m)

Otwiera plik o nazwie s w trybie m i kieruje na niego strumień plikowy

fs.open(s,m)

Otwiera plik o nazwie s w trybie m i ustawia fs, aby się do niego odwoływał

fs.is_open()

Sprawdza, czy fs jest otwarty

Dla strumieni plikowych nazwa pliku jest łańcuchem w stylu języka C.

Tryby strumieni

Pliki można otwierać w jednym z kilku trybów.

ios_base::app

Dodawanie na końcu

ios_base::ate

Otwieranie i przechodzenie na koniec

ios_base::binary

Tryb binarny. Uwaga na zachowanie charakterystyczne dla danego systemu

ios_base::in

Do odczytu

ios_base::out

Do zapisu

ios_base::trunc

Przycina plik do długości 0.

Dokładny efekt otwarcia pliku może zależeć od systemu operacyjnego. Jeśli system nie może spełnić żądania otwarcia pliku w określonym trybie, powstanie strumień w trybie innym niż good().

Przykład:

void my_code(ostream& os); // Funkcja my_code może używać dowolnego strumienia wyjściowego
ostringstream os; // o oznacza output (wyjście)
ofstream of("my_file");
if (!of) error("Nie można otworzyć pliku 'my_file' w trybie zapisu.");
my_code(os); //Użycie łańcucha
my_code(of);

Obsługa błędów

Możliwe są cztery stany strumieni iostream:

  1. good() – operacje zakończone sukcesem

  2. eof() – napotkano koniec danych wejściowych (koniec pliku)

  3. fail() – stało się coś nieprzewidzianego (np. szukano cyfry, a znaleziono znak «x»)

  4. bad() – stało się coś nieprzewidzianego i poważnego (np. wystąpił błąd odczytu z dysku)

Za pomocą wywołania s.exceptions() można zmusić strumienie iostream do zgłaszania wyjątków, gdy przechodzą w stan inny niż good().

Operacje wykonywane na strumieniach w stanie innym niż good() nie mają żadnego efektu.

Strumienia iostream można użyć jako warunku . Prawdzie (sukcesowi) odpowiada stan good() tego strumienia. Jest to podstawa popularnej techniki odczytywania strumieni wartości.

X x; // Bufor wejściowy do przechowywania jednej wartości typu X
while (cin>>x)
{
// Działania na x
}
// Tutaj przekazywane jest sterowanie, gdy operator >> nie może wczytać
// kolejnej wartości typu X ze strumieni cin

Operacje wejściowe

Prawie wszystkie operacje wejściowe znajdują się w nagłówku <istream>. Wyjątkiem są operacje wczytywania danych do łańcuchów, które znajdują się w nagłówku <string>.

Operacje do formatowanego wstawiania

in >> x

Wczytuje do x dane z in zgodnie z typem x

getline(in,s)

Wczytuje wiersz tekstu z in do łańucha s

Jeśli nie jest napisane inaczej, operacje strumieni wejściowych (istream) zwracają referencje do swoich strumieni, dzięki czemu można budować łańcuchy tych operacji, np. cin>>x>>y;.

Operacje do nieformatowanego wstawiania

x=in.get()

Wczytuje jeden znak z in i zwraca jego wartość całkowitoliczbową.

in.get(c)

Wczytuje znak z in do c.

in.get(p,n)

Wczytuje najwyżej n znaków z in do tablicy, zaczynając od p

in.get(p,n,t)

Wczytuje najwyżej n znaków z in do tablicy, zaczynając od p. Argument t określa znak końcowy.

in.getline(p,n)

Wczytuje najwyżej n znaków z in do tablicy, zaczynając od p. Usuwa znak końca z in.

in.getline(p,n,t)

Wczytuje najwyżej n znaków z in do tablicy, zaczynając od p. Argument t określa znak końcowy. Usuwa znak końca z in.

in.read(p,n)

Wczytuje najwyżej n znaków z in do tablicy, zaczynając od p.

x=in.gcount()

x określa liczbę znaków wczytanych przez ostatnią operację bez formatowania na in.

Funkcje get() i getline() wstawiają 0 na końcu ciągu znaków zapisanego w p[0].

Funkcja getline() usuwa znak końca (t) z danych wejściowych, jeśli taki tam jest. Natomiast funkcja get() tego nie robi. Funkcja read(p,n) nie wstawia 0 do tablicy za wczytanymi znakami.

Sformatowane operatory wejściowe są łatwiejsze w użyciu i mniej podatne na błędy niż ich niesformatowane odpowiedniki.

Operacje wyjściowe

Prawie wszystkie operacje wyjściowe znajdują się w nagłówku <ostream>. Wyjątkiem są operacje wysyłania danych do łańcuchów, które znajdują się w nagłówku <string>.

out << x

Zapisuje x w out zgodnie z typem x

out.put(c)

Zapisuje znak c w out

out.write(p,n)

Zapisuje znaki p[0] ..p[n-1] w out

Jeśli nie jest napisane inaczej, operacje strumieni wyjściowych (ostream) zwracają referencje do swoich strumieni, dzięki czemu można budować łańcuchy tych operacji, np. cin<<x<<y;.

Formatowanie

O formacie strumieni wejścia i wyjścia decydują następujące czynniki:

  • typ obiektu,

  • stan strumienia,

  • informacje dotyczące lokalizacji (zobacz nagłówek <locale>)

  • jawnie wykonywane operacje

Standardowe manipulatory

W bibliotece standardowej dostępne są manipulatory pozwalające na różne sposoby określać formatowanie. Definicje tych manipulatorów znajdują się w nagłówkach <ios>, <istream>, <ostream>, <iostream> oraz <iomanip> (manipulatory pobierające argumenty).

s<<boolalpha

Zamienia wartości logiczne true i false na ich reprezentację symboliczną (wejście i wyjście)

s<<noboolalpha

s.unsetf(ios_base::boolalpha)

s<<showbase

Powoduje dodanie przedrostka 0 do danych w formacie ósemkowym i 0x do danych w formacie szesnastkowym

s<<noshowbase

s.unsetf(ios_base:: showbase)

s<<showpoint

Powoduje wyświetlenie przecinka dziesiętnego

s<<noshowpoint

s.unsetf(ios_base:: showpoint)

s<<showpos

Dodaje znak + przed liczbami dodatnimi

s<<noshowpos

s.unsetf(ios_base:: showpos)

s>>skipws

Pomija białe znaki

s>>noskipws

s.unsetf(ios_base:: skipws)

s<<uppercase

Zamienia w numerycznych danych wyjściowych małe litery na wielkie, np. drukuje 1.2E10 i 0X1A2 zamiast 1.2e10 i 0x1a2

s<<nouppercase

Wyświetli np. x i e, a nie X i E

s<<internal

Dodaje znaki wypełnienia wewnątrz ciągu

s<<left

Dodaje znaki wypełnienia za wartością

s<<right

Dodaje znaki wypełnienia przed wartością

s<<dec

Dziesiętna podstawa liczb całkowitych

s<<hex

Szesnastkowa podstawa liczb całkowitych

s<<oct

Ósemkowa podstawa liczb całkowitych

s<<fixed

Format dddd.dd liczb zmiennoprzecinkowych

s<<scientific

Format naukowy – d.ddddEdd

s<<endl

Wstawia znak «n» i wywołuje flush

s<<ends

Wstawia znak «0»

s<<flush

Opróżnia strumień

s>>ws

Zjada białe znaki

s<<resetiosflags(f)

Usuwa znaczniki f

s<<setiosflags(f)

Ustawia znaczniki f

s<<setbase(b)

Drukuje na wyjściu liczby całkowite w formacie o podstawie b

s<<setfill(c)

Ustawia c jako znak wypełniający

s<<setprecision(n)

Ustawia precyzję na n cyfr

s<<setw(n)

Ustawia szerokość następnego pola na n znaków

Wszystkie te operacje zwracają referencje do swojego pierwszego argumentu (strumienia) – s.

Na przykład:

cout << 1234 << ',' << hex << 1234 << ',' << oct << 1234 << endl;

zwróci poniższy wynik:

1234,4d2,2322

Natomiast poniższy kod:

cout << '(' << setw(4) << setfill('#') << 12 << ") (" << 12 << ")\n";

zwróci:

(##12) (12)

Aby bezpośrednio ustawić ogólny format wyjściowy liczb rzeczywistych, należy napisać poniższy kod:

b.setf(ios_base::fmtflags(0), ios_base::floatfield);