Wejście – wyjście strumieniowe
Transkrypt
Wejście – wyjście strumieniowe
PARADYGMATY PROGRAMOWANIA Wykład 6 Wejście – wyjście strumieniowe stdin – standardowy strumień wejściowy stdout – standardowy strumień wyjściowy stderr – standardowy strumień komunikatów o błędach pliki - inne źródła wejścia / wyjścia programu plik jest uporządkowanym strumieniem bajtów Trybu zapisu / odczytu ze strumieni binarny – strumień jest nieinterpretowanym przez procedury zapisu/odczytu ciągiem bajtów tekstowy – zakłada się, że strumień jest zapisem ciągu znaków pisarskich (znak może składać się z więcej niż jednego bajtu – zależnie od systemu kodowania), procedury wejścia / wyjścia mogą dokonywać konwersji pomiędzy postacią binarną a ustaloną postacią tekstową Ogólne zasady wykorzystywania strumieni w programach • Strumienie, z których chce korzystać program są dla programisty reprezentowane przez obiekty specjalnie do tego celu zaprojektowanych klas. • stdin jest reprezentowany za pomocą predefiniowanego obiektu o nazwie cin • stdout – jest reprezentowany za pomocą predefiniowanego obiektu o nazwie cout • Strumienie (z wyjątkiem standardowych) muszą być przed użyciem otwarte • Przyjęto konwencję, że dla klas reprezentujących strumienie definiuje się operatory wejścia ( >> ) i wyjścia ( >> ) o następujących cechach: • lewym operandem jest referencja do strumienia, • prawym operandem jest obiekt lub l-wyrażenie typu prostego, który jest żródłem danych dla operacji, • wartością operatora jest referencja do strumienia przekazanego jako lewostronny operand – wówczas można wielokrotnie używać operatorów << lub >> w jednym wyrażeniu. • Przeciążone operatory << i >> są zdefiniowane dla typów wbudowanych (int, char, char*, double float ) oraz dla niektórych typów definiowanych w bibliotekach standardowych (np. dla typu string). • Dla klas definiowanych przez programistę może on zdefiniować operator << i >> w sposób specyficzny dla swojego typu danych. Hierarchia klas do obsługi wejścia wyjścia strumieniowego cin – obiekt klasy istream cout – obiekt klasy ostream Operacje na plikach: ifstream – (input file stream) klasa pozwalająca na odczyt z pliku ofstream – (output file stream) klasa pozwalająca na zapis do pliku fstream - klasa pozwalająca na odczyt i zapis w pliku Operacje na ciągach znaków – pozwalają traktować bufory znakowe jak strumienie, w szczególności można w ten sposób dokonywać konwersji danych pomiędzy postacią znakową i binarną. Strumienie są buforowane – nie ma pewności, że wykonanie operatora wyjścia << spowoduje natychmiastowe pojawienie się danych na urządzeniu fizycznym. metoda flush() - wymusza opróżnienie bufora i zapis danych do urządzenie: cout.flush(); Działanie operatora odczytu >> w odniesieniu do danych typu char * (łańcuchy znaków) • operator odczytuje dane z pominięciem poprzedzających białych znaków (spacja, tabulacja, nowa linia) i kończy odczytywanie po napotkaniu pierwszego białego znaku po "nie-białym" • wniosek – nie można odczytywać napisów zawierających białe znaki • metoda get pozwala odczytać łańcuch z białymi znakami istream & get( char &c); odczyt pojedynczego znaku istream & get( char *buf, int n, char term = '\n' ); odczytuje nie więcej niż n-1 znaków do bufora buf, kończy po napotkaniu znaku term, znak kończący nie jest odczytywany i pozostaje w strumieniu, znak '\0' jest zapisywany w buforze istream & getline(); podobnie jak get ale znak nowej linii jest usuwany ze strumienia lecz nie trafia do bufora W przypadku osiągnięcia końca strumienia ( Ctrl-Z ) funkcje zwracają referencję pustą (NULL) char c; while (cin.get( c ) != NULL) printf("%d\n", c ); while (cin.get( buf, 50 ) != NULL) printf("%s\n", buf ); // BŁĄD – zapetlenie programu Przeciążanie operatorów << i >> dla typów zdefiniowanych przez programistę class compl { friend ostream & operator << ( ostream & out_strm, compl nmb ); friend istream & operator >> ( istream & out_strm, compl & nmb ); private: double re, im; public: compl( double re = 0.0, double im = 0.0 ); void set_re ( double re ); void set_im( double im ); }; ostream & operator << ( ostream & out_strm, compl nmb ) { out_strm << nmb.re << " " << nmb.im ; return out_strm; } istream & operator >> ( istream & in_strm, compl & nmb ) { in_strm >> nmb.re >> nmb.im ; return in_strm; } Sprawdzanie statusu strumienia: class ios { public: enum is_state( goodbit, eofbit, failbit, badbit ); int bad() const; // wystąpił błąd int eof() const; // osiągnięto koniec pliku int fail() const; // wystąpił błąd – nie utracono danych int good() const; // następna operacja może się powiesc // ... }; Badanie stanu • za pomoca metod bad(), eof(), fail(), good() • za pomoca metody io_state rdstate(); Formatowanie i manipulatory • manipulator – obiekt modyfikujący sposób działania operatorów strumieniowych • manipulatory z parametrami zdefiniowane w pliku nagłówkowym iomanip.h określanie formatu liczby całkowitej • oct – ósemkowy, • hex – szesnastkowy • dec – dziesiętny UWAGA: konwersji poddawana jest wartość kodu U2 liczby, np hex dla –1 -> ffffffff oct dla –1 -> 37777777777 określanie szerokości pola • setw( int width ) – określa szerokośc pola na wyświetlenie następnej danej • setfill( char filler = ' ' ) – określa znak wypełniający pole – obowiązuje aż do odwołania • setprecision ( int precision = 6 ) – określenie ilości miejsc po przecinku dla liczb zmiennoprzecinkowych Operacje na plikach wymagają włączenia pliku fstream (bez .h – konwencja nazywania plików nagłówkowych w C++) oraz uaktywnienia przestrzeni nazw std #include <fstream> using namewspace std; Deklaracja zmiennej plikowej: fstream file; otwarcie pliku – metoda open void open( const char *s, ios_base::openmode mode = ios_base::in | ios_base::out ); np. file.open( "c:\\test.txt", ios::out | ios::app ) ... file.close(); Tryby otwarcia: in, out, app, trunc nocreate, noreplace, binary, ate Operacje binarne: write( char *buffer, int size ); read( char *buffer, int size ); Pozycjonowanie w pliku class ios { enum seek_dir (beg, curr, end ); istream seekg( int rel_pos, seek_dir d = ios::beg ); int tellg(); ostream seekp( int rel_pos, seek_dir d = ios::beg ); int tellp(); } Operacje wejscia-wyjscia w pamięci: • strumień może być symulowany w pamięci – w tablicy znakowej (lub za pomocę typu string) • wszystkie operacje które moga byc wykonywane na ostream moga być też wykonane na ostrstream, Podobnie dla istream i istrstream istrstream::istrstream( char * buf, ostrstream::istrstream( char * buf, int size ); int size ); #include <iostream> using namespace std ; #include <iomanip> #include <strstream> // <--- bo uzywamy ostrstream #include <sstream> // <-- bo uzywamy ostringstream /*******************************************************/ int main() { int nr_silnika = 4 ; float temperat = 156.7123 ; char komunikat[80] ; ostrstream strumyk(komunikat, sizeof(komunikat) ); // strumyk << "Awaria silnika "<< setw(2) << nr_silnika << ", temperatura oleju " << setprecision(2) << temperat << " stopni C \n" ; // cout << komunitat; strumyk.seekp(8, ios_base::beg); strumyk << "XYZ" ; cout << "Po zabawie z pozycjonowaniem :\n" << komunikat ; // // ##################### NOWY STYL ######################" ostringstream strumyk2; // strumyk2 << "Awaria silnika "<< setw(2) << nr_silnika << ", temperatura oleju " << setprecision(2) << temperat << " stopni C \n" ; // if(!strumyk2) cout << "jakis blad "<< endl; strumyk2 << "Musisz cos zrobic !!!\n" << ends ; cout << strumyk2.str() <, endl; strumyk2.seekp(8, ios_base::beg); strumyk2 << "XYZ" ; cout << "Po zabawie z pozycjonowaniem :\n" << strumyk2.str() ; } // //