Wykład 2 Operacje wejściawyjścia w C++ Ewa Gajda
Strumienie Operacje wejścia-wyjścia w C++ realizowane są przy pomocy tak zwanych strumieni. Strumieo można sobie wyobrażad jako ciąg znaków bądź bajtów płynący od źródła do ujścia, np. z klawiatury do pamięci lub z pamięci na dysk twardy. Czytanie lub wypisywanie bajtów płynących strumieniem może byd realizowane na dwóch poziomach: Na poziomie wysokim interpretujemy zawartośd kolejnych bajtów płynących strumieniem Na przykład pewne bajty interpretujemy jako znaki kooca linii, tabulacji, kooca pliku Ciągi bajtów mogą byd (na żądanie) interpretowane jako zapisy liczb Na poziomie niskim wiernie odtwarzamy zawartośd strumienia bajt po bajcie.
Strumienie Ze względu na różne stosowane standardy zapisu znaków narodowych, jeden znak w strumieniu może zajmowad jeden dwa i więcej bajtów. Z tego powodu w bibliotece standardowej C++ strumienie realizowane są jako szablony klas, których parametrem jest typ stosowanych znaków. Strumienie realizowane są w C++ jako obiekty następujących szablonów klas zdefiniowanych w przestrzeni nazw std basic_istream<> - szablon klas udostępniających formatowane strumienie wejściowe (wczytujące do pamięci) basic_ostream<> - szablon klas udostępniających formatowane strumienie wyjściowe (wypisujące z pamięci) basic_iostream<> - szablon klas pochodnych od powyższych dwóch, umożliwia tak czytanie jak i pisanie Szablony te są zdefiniowane w standardowej bibliotece C++.
Pliki nagłówkowe Biblioteka standardowa C++ dostarcza m.in. następujące pliki nagłówkowe: <iosfwd> - deklaracje zapowiadające klas strumieniowych. <istream> - definicje szablonu klas basic_istream<> oraz basic_iostream<> <ostream> - definicje szablonu klas basic_ostream<> <iostream> - definicje globalnych obiektów strumieni <fstream> - operacje wejścia-wyjścia na plikach <strstream> - operacjach wejścia-wyjścia z/do tablic <sstream> - operacje wejścia-wyjścia z/do łaocuchów klasy string
Strumienie predefiniowane Dla naszej wygody kompilator automatycznie definiuje cztery strumienie dla typu char: cout standardowy strumieo wyjścia (zwykle ekran). cin standardowy strumieo wejścia (zwykle klawiatura). cerr standardowy strumieo dla komunikatów o błędach (zwykle także ekran). clog standardowy strumieo protokołów (logów)
Operatory << i >> Formatowane wpisywanie informacji do strumienia i czytanie ze strumienia zrealizowano w C++ poprzez szablony przeładowujące operatory << i >>. Przykładowo mamy do dyspozycji następujące funkcje biblioteczne dla klasy ostream: ostream& operator<<(ostream& wyjscie, int i) ostream& operator<<(ostream& wyjscie, float f) ostream& operator<<(ostream& wyjscie, char* c) Ponieważ funkcje te zwracają referencję do strumienia wyjscie (otrzymanego jako argument), możliwe jest kaskadowe wywołanie: int ilosc; float waga; char opis[20];... cout << "Opis: " << opis << " Ilość: " << ilosc << " Waga: " << waga;
Znaczniki i manipulatory Do sterowania pracą ze strumieniem służą manipulatory - specjalne wartości, które można wstawiad do strumienia albo z niego wyjąd po to, by wywoład zamierzony efekt uboczny polegający na zmianie sposobu formatowania: dec -- włącz konwersję dziesiątkową hex -- włącz konwersję szesnastkową oct -- włącz konwersję ósemkową boolalpha -- włącz tekstowy zapis wartości logicznych noboolalpha -- wyłącz tekstowy zapis wartości logicznych flush -- opróżnij bufor endl -- wypisz znak kooca linii i opróżnij bufor ends -- wypisz znak NULL ('\0') ws -- przeskocz wszystkie białe znaki setw(int n) -- ustaw szerokośd drukowania na n pól setfill(int c) -- znak c zostanie użyty do wypełnienia nadmiarowych pól setprecision(int n) -- określa dokładnośd po przecinku wypisywanej liczby Przykład
Nieformatowane operacje wejścia Chod zdarza się to rzadziej, czasem chcemy wiedzied dokładnie co płynie strumieniem i formatowanie przestaje byd udogodnieniem, a zaczyna byd utrudnieniem. Wtedy można posłużyd się funkcjami realizującymi nieformatowane operacje wejścia-wyjścia. istream& get(char& z); Powyższa funkcja wyjmuje ze strumienia jeden bajt i umieszcza go w podanej zmiennej z. Jako rezultat zwraca referencję do strumienia (chyba, że napotka znak kooca pliku EOF, wtedy zwraca NULL). Umożliwia to wołanie kaskadowe cin.get(a).get(b).get(c);
Nieformatowane operacje wejścia int get(void); Powyższa funkcja zwraca wczytany znak. istream& get(char* gdzie, int ile, char ogran='\n'); Funkcja pozwala na wczytanie maksymalnie ile bajtów do tablicy o adresie gdzie. Znak ogran to znak, po którego napotkaniu wczytywanie jest przerywane. istream& getline(char* gdzie, int ile, char ogran='\n'); Funkcja działa jak poprzednia, ale dodatkowo wyjmuje też sam ogranicznik ze strumienia. istream& read(char* gdzie, int dlugosc); Funkcja czyta podaną ilośd znaków do podanej tablicy. Sygnalizuje błąd, jeśli napotka po drodze znak kooca pliku.
Nieformatowane operacje wyjścia ostream& put(char z); Funkcja wstawia do strumienia podany znak. Jako rezultat zwraca referencję do strumienia (chyba, że z jakiegoś powodu operacja pisania się nie uda, wtedy zwraca NULL). ostream& write(const char* skad, int dlugosc); Funkcja wstawia do strumienia podaną ilośd bajtów z podanej tablicy.
Operacje wejścia-wyjścia na plikach Operacje wejścia-wyjścia na plikach dla typu char obsługiwane są w C++ przez ifstream, ofstream oraz fstream (biblioteka standardowa C++). Aby czytad z pliku lub do niego pisad należy: zdefiniowad strumieo, czyli wykreowad odpowiedni obiekt jednej z powyższych klas określid z jakim plikiem strumieo ten ma się komunikowad i otworzyd ten plik przeprowadzid żądane operacje wejścia-wyjścia zamknąd plik, gdy uznamy, że praca z nim została zakooczona zlikwidowad strumieo. Przykład
Otwieranie i zamykanie plików void ifstream::open(const char* nazwa, int tryb=ios::in); void ofstream::open(const char* nazwa, int tryb=ios::out); void fstream::open(const char* nazwa, int tryb); są funkcjami składowymi, które otwierają plik o podanej nazwie i wiążą go ze strumieniem w trybie określonym parametrem tryb. Ponowne otwarcie pliku za pomocą obiektu klasy ofstream powoduje usunięcie całej dotychczasowej zawartości pliku. Tryb binarny to tryb, w którym wyłączona jest wszelka interpretacja znaków, nawet znaku kooca pliku.
Otwieranie i zamykanie plików Dostępne tryby otwarcia pliku zdefiniowane są w klasie ios. Są to bitowe flagi, które mogą byd łączone przy użyciu operatora. Zbiera je poniższa tabela: Tryb ios::in ios::out ios::ate ios::app ios::trunc ios::noncreate ios::binary Znaczenie otwórz do czytania otwórz do pisania otwórz i ustaw się na koocu zawartości otwórz do dopisywania otwórz, a jeśli plik istnieje, skasuj starą treśd jeżeli plik nie istnieje operacja kooczy się porażką otwórz w trybie binarnym Przykład
Otwieranie i zamykanie plików Funkcje void ifstream::close(); void ofstream::close(); void fstream::close(); to funkcje składowe, które zamykają plik powiązany z danym strumieniem. Od tego momentu nie można pisad/czytad do/z tego strumienia. Można jednak otworzyd inny plik i powiązad go z tym strumieniem. Jeden strumieo może byd używany wielokrotnie, z wieloma z plikami.
Funkcje pomocnicze przy operacjach na plikach bool good() zwraca wartośd true, jeśli w trakcie pracy strumienia nie wystąpił żaden błąd, w przeciwnym razie zwraca false. bool eof() zwraca wartośd true gdy napotkany został koniec pliku, w przeciwnym razie zwraca false. bool fail() zwraca wartośd true, jeśli w trakcie pracy strumienia pojawił się błąd, ale strumieo ciągle jeszcze nadaje się do pracy. Na przykład oczekiwano w strumieniu liczby, a znaleziono literę. W przeciwnym razie funkcja zwraca false. bool bad() zwraca wartośd true, jeśli strumieo nie nadaje się do pracy. Na przykład chcemy wczytywad z pliku, który nie istnieje. W przeciwnym razie funkcja zwraca false.
Przykład - wczytanie pliku i wypisanie zawartości na ekranie.