Strumienie Bufrwanie danych Bufrwanie strumieni Dane znajdujące się w strumieniu należy interpretwać zgdnie z ich znaczeniem, ale zawsze należy pamiętać, że są t p prstu sekwencje bajtów. Za bsługę bajtwą danych strumieniwych dpwiedzialny jest biekt typu streambuf (dkładny typ zależy d teg, czy jest t strumień reprezentujący standardwe we/wy, plik, itd.) D teg biektu mżna sięgać bezpśredni: mżna np. przesunąć się kreślną liczbę bajtów bez ich frmatwania przez strumień 41 Bufrwanie strumieni Aby umżliwić sięgnięcie d biektu streambuf, każdy biekt istream zawiera metdę rdbuf(): basic_streambuf<elem, Traits> *rdbuf( ) cnst; zwraca wskaźnik d bufra strumieniweg. basic_streambuf<elem, Traits> *rdbuf( basic_streambuf<e, T> *_Sb); umieszcza bufr strumieniwy pdany w argumencie w miejsce pprzednieg, a wskaźnik d pprzednieg zwraca jak rezultat. Bufrwanie strumieni przykład: int main( ) { fstream file( "Test3.txt" ); streambuf *x = cut.rdbuf( file.rdbuf( ) ); // pdmiana.. cut << "test1" << endl; // dane są zapisywane d pliku cut.rdbuf(x); cut << "test2" << endl; ifstream in( "Test3.txt" ); cut << in.rdbuf(); // jednym ruchem cały plik! Okn terminala: test2 test1 42 43 Bufrwanie strumieni przykład: Aby przekazać wszystkie znaki z jedneg strumienia d drugieg napisaliśmy: cut << in.rdbuf(); Zastępuje t żmudne (i pdatne na błędy) dczytywanie klejnych znaków lub wierszy, jest też szybsze. Przypmnienie metda get: int_type get( ); basic_istream<elem, Tr>& get(elem& _Ch); basic_istream<elem, Tr>& get(elem* str, streamsize cunt); basic_istream<elem, Tr>& get(elem* str, streamsize cunt, Elem _Delim); Przerywa swje działanie zaraz p znalezieniu granicznika, ale teg granicznika już nie pbiera ze strumienia. char c[10]; c[0] = cin.get( ); // pbiera jeden element cin.get( c[1] ); // pbiera jeden element cin.get( &c[2],3 );// pbiera d naptkania znaku \n, ale max. 3 cin.get( &c[4], 4, '7' );// pbiera d naptkania znaku 7, ale max. 4 cut << c << endl; 44 45 1
Bufrwanie strumieni Zawartść pliku Test.txt: W klasie istream istnieje również wersja metdy get, która ptrafi pisać bezpśredni d biektu streambuf (a nie tylk d C-napisu): basic_istream<elem, Tr>& get( basic_streambuf<elem, Tr>& strbuf); ifstream in( "Test.txt" ); streambuf &sb = *cut.rdbuf(); while(!in.get(sb).ef()) cut << char(in.get()); in.get(sb) pbiera wiersz znaków d naptkania \n, ale teg znaku już nie pbiera i wysyła d sb Kiedy Kara Mustafa, wielki mistrz Krzyżaków, szedł z licznymi zastępy przez Alpy na Kraków, d brny swych psad zawsze będąc skry pbił g pd Grunwaldem król Stefan Batry. basic_istream<elem, Tr>& get( basic_streambuf<elem, Tr>& strbuf, Elem _Delim); in.get() pbiera jeden znak Wada: Jeżeli w pliku trafi się pusta linia, in.get(sb) zwróci znak błędu -1 i nie przejdzie d dczytu następnej 46 linii. 47 ifstream in( "Test3.txt" ); streambuf &sb = *cut.rdbuf(); while(!in.get(sb).ef()) { if (in.fail()) // wystąpił błąd (znalezin pusty wiersz) in.clear(); // czyścimy flagę błędu cut << char(in.get()); in.get(sb) pbiera wiersz znaków d naptkania \n, ale teg znaku już nie pbiera i wysyła d sb Przeszukiwanie strumieni we/wy W każdym typie strumienia istream istnieje pjęcie następneg znaku d dczytania lub zapisania. Mżemy przesuwać się p znakach w strumieniu w przód i w tył, wskazując kreślne bezwzględne płżenie alb przesunięcie względem płżenia bieżąceg. Określanie płżenia: ps_type tellp( ); ps_type tellg( ); (d użycia z stream) (d użycia z istream) in.get() pbiera jeden znak 48 49 ifstream file; char c; Przesunięcie się w strumieniu: basic_stream& seekp( ps_type _Ps ); basic_istream& seekg( ps_type _Ps ); (d użycia z stream) (d użycia z istream) file.pen( "basic_istream_tellg.txt" ); i = file.tellg( ); cut << c << " " << i << endl; // pjawią się: znak 0 i = file.tellg( ); cut << c << " " << i << endl; // pjawią się: znak 1 Metdy jednargumentwe pzwalają przesunąć się w kreślne miejsce: fstream x( "itest.txt" ); int i = x.tellp( ); // zwróci 0 x << "1234567890"; i = x.tellp( ); // zwróci 10 x.seekp( i-5 ); x << " "; // gdzie zstanie umieszczny znak spacji? 50 51 2
Przesunięcie się w strumieniu: basic_stream& seekp( ff_type _Off, is_base::seekdir _Way ); basic_istream& seekg( ff_type _Off, is_base::seekdir _Way ); Metdy dwuargumentwe pzwalają przesunąć się kreślny ffset względem pczątku, kńca lub bieżąceg płżenia: is::beg d pczątku (w ANSI C stdi: SEEK_SET) is::cur d aktualneg płżenia (w ANSI C stdi: SEEK_CUR) is::end d kńca strumienia (w ANSI C stdi: SEEK_END) Wartść przesunięcia jak liczba ddatnia przesuwa w praw a ujemna w lew. Przesunięcie się w strumieniu przykład: fstream x( "itest.txt" ); int i = x.tellp( ); // pbieramy aktualne płżenie w pliku x << "1234567890"; i = x.tellp( ); // pbieramy aktualne płżenie w pliku x.seekp( i - 5 ); // zmieniamy aktualne płżenie w pliku x << " "; x.seekp( -2, is::end ); // jeszcze raz zmieniamy.. x << "#"; // P wyknaniu kdu plik zawiera: 12345 78#0 52 53 ifstream file; char c, c1; file.pen( test.txt" ); file.seekg(2); cut << c << endl; file.seekg( 0, is_base::beg); cut << c << endl; file.seekg( -1, is_base::end); file >> c1; cut << c1 << endl; Plik wejściwy test.txt: 0123456789 W knie knsli: 2 0 9 Twrzenie biektu strumienia umżliwiająceg pisanie i czytanie ifstream in2("test.txt", is::in is::ut); stream ut2(in2.rdbuf()); cut << in2.rdbuf() << endl; ut2 << "ile Rman ładny dyndał na mreli"; ut2.seekp(0, is::beg); ut2 << "jeż leje lwa paw leje lżej"; in2.seekg(0, is::beg); cut << in2.rdbuf() << endl; Plik wejściwy test.txt:!!!!!@@@@@#####$$$$$%%%%%----- W knie knsli:!!!!!@@@@@#####$$$$$%%%%%----- jeż leje lwa, paw leje lżej---ile Rman ładny dyndał na mreli? Dlaczeg tekst pierwszy ddawany jest na kńcu pliku? 54 55 Strumienie pwiązane z łańcuchami <sstream> Bardz przydatne np. d parswania napisów (analizy składniwej napisów list słów ustalnej składni) Łańcuchwe strumienie wejściwe #include <cassert> #include <cmath> // fabs() #include <limits> // epsiln() #include <sstream> #include <string> int main( ) { istringstream s("47 1.414 T tylk taki test"); duble f; s >> i >> f; assert(i == 47); duble relerr = (fabs(f) - 1.414) / 1.414; assert(relerr <= numeric_limits<duble>::epsiln()); 56 57 3
Łańcuchwe strumienie wejściwe int main( ) { istringstream s("47 1.414 T tylk taki test"); duble f; s >> i >> f; assert(i == 47); duble relerr = (fabs(f) - 1.414) / 1.414; assert(relerr <= numeric_limits<duble>::epsiln()); string buf2; s >> buf2; assert(buf2 == "T"); cut << s.rdbuf() << endl; // " tylk taki test" Łańcuchwe strumienie wejściwe Pbieranie wartści d zmiennych dbywa się zgdnie z ich typem: istringstream s("47 1.414 T tylk taki test"); duble f; s >> i >> f; // i=47 f = 1.414 Gdyby zmienić klejnść liczb w ciągu: istringstream s("1.414 47 T tylk taki test"); wtedy: s >> i >> f; // i=1 f = 0.414 58 59 Łańcuchwe strumienie wyjściwe cut << "napisz wartści int, flat i string: "; flat f; cin >> i >> f; cin >> ws; // drzuć ewentualne białe znaki string stuff; getline(cin, stuff); // pbierz d kńca wiersza stringstream s; s << "integer = " << i << endl; s << "flat = " << f << endl; s << "string = " << stuff << endl; string result = s.str(); cut << result << endl; Użycie dwukierunkweg strumienia łańcuchweg string text = "W Mskwie na Placu Czerwnym"; stringstream ss(text); ss.seekp(0, is::end); ss << " rzdają samchdy."; assert(ss.str() == "W Mskwie na Placu Czerwnym rzdają samchdy."); ss.seekg(18, is::beg); string wrd; ss >> wrd; assert(wrd == "Czerwnym"); ss.seekp(2, is::beg); ss << "Kijwie"; ss.seekg(29, is::beg); ss >> wrd; assert(wrd == "rzdają"); ss.seekp(37, is::beg); ss << "rwery.."; cut << ss.str() << endl; 60 Fałsz: w Kijwie nie ma placu Czerwneg 61 Binarny dstęp d danych: D dczytu danych ze strumienia w taki spsób, aby mżna je był interpretwać jak ciąg binarny! służy: basic_istream& read( char_type *_Str, streamsize _Cunt ); Funkcja dczytuje kreślną liczbę bajtów _Cunt i zapisuje ją pd wskazany adres wskaźnik _Str. Jeżeli wcześniej naptka kniec pliku, przerywa dczyt i kńczy działanie ustawiając dpwiednią flagę błędu. Strumienie Binarny dstęp d danych Ciąg binarny ciąg bajtów (nie bitów!). Interpretacja danych dwlnych typów jak ciąg binarny plega na dczytaniu tych danych z pminięciem infrmacji ich strukturze, tj. bajt p bajcie (nie bit p bicie!). 63 4
Binarny dstęp d danych: D zapisu danych d strumienia służy: basic_stream& write( cnst char_type *_Str, streamsize _Cunt ); Aby zastswać tę funkcję d krzystania z pliku w trybie binarnym, należy bszary pamięci, d który dane mają trafić (lub skąd mają być pbrane), zrzutwać na wskaźniki typu cnst char_type* (zapis d strumienia) lub char_type* (dczyt ze strumienia). Binarny dstęp d danych: struct Blczek { int a; duble b; char c; ; int main( ) { fstream fx( "test.txt", is::binary); Blczek s={3,3.14,'a'; cnst char *pm = (cnst char*)&s; fx.write((char*)&s, sizef(s)); fx.write(pm, sizef(s)); fx.clse(); ifstream ifx( "test.txt",is::binary); Blczek s2; char *pm2 = (char*)&s2; ifx.read((char*)&s2, sizef(s2)); ifx.read(pm2, sizef(s2)); cut << s2.a << s2.b << s2.c; 64 65 Krzystanie z wyjątków pzwala ddzielić kd bsługi błędu d kdu wyknania zadania Zamiast umieszczać w kdzie bsługi zadania sekwencje instrukcji dpwiedzialne za pprawne zachwanie prgramu w razie wystąpienia błędu, t piszemy kd bsługi zadania tak, jakbyśmy zakładali, że wszystk dbędzie się bez prblemów. Kd bsługi błędu umieszczamy natmiast w innym miejscu prgramu i tylk wiążemy razem te dwa blki kdu współzależnścią. 67 Wystąpienie błędu pwduje natychmiastwe przerwanie bsługi zadania i przekazanie sterwania d inneg bszaru kdu, gdzie znajdują się instrukcje bsługujące błąd. Kd bsługi zadania mżna pdzielić na kilka sekcji, które uważamy za funkcjnalnie zamknięte całści. Taka sekcja mże w całści wyknać się pprawnie lub w całści zstać niewyknana Aby mechanizm wyjątków mógł działać adekwatnie d sytuacji błędnej, musi zstać przekazana infrmacja rdzaju błędu, jaki wystąpił. D teg celu służą biekty, w których mżna zawrzeć infrmacje indywidualnych klicznściach zdarzenia. 68 69 5
Pdsumwując, d wprwadzenia wyjątków ptrzebne są: 1) spsób znakwania sekcji kdu, której wiadm, że w trakcie jej wyknania mże być rzucny wyjątek, 2) spsób znakwania sekcji kdu, która nie jest zwykłym fragmentem prgramu, ale reprezentuje kd mający się wyknać w przypadku rzucenia wyjątku, 3) instrukcja rzucania wyjątku, która spwduje przeniesienie sterwania, 4) klasa na pdstawie której twrzne będą biekty zawierające infrmacje klicznściach, w których wystąpił błąd. Rzucanie wyjątków instrukcja thrw Pwduje: 1) przerwanie wyknywania bieżąceg kdu, 2) wygenerwanie biektu przechwująceg infrmacje klicznściach błędu, 3) przeniesienie sterwania z bieżąceg kdu d miejsca, które jest w stanie przyjąć biekt daneg typu i wykrzystać zawarte w nim infrmacje d bsługi sytuacji błędnej. 70 71 Rzucanie wyjątków Jeżeli w jakimś miejscu kdu wystąpiła sytuacja niepprawna, t zamiast ustawiać flagę błędu, lub natychmiast kńczyć działanie funkcji pleceniem return, które zwraca kd błędu, w tym miejscu umieszczamy plecenie rzucenia wyjątku, np.: if (x>0) y = sqrt(x); else return -1; // stary spsób, typwy dla języka C // alb: thrw MyErrr("nieprawidłwa próba pierwiastkwania"); // nwy spsób, typwy dla C++. // MyErrr t nazwa klasy, której biekt twrzymy C się stanie dalej?.. 1) Jeżeli jesteśmy wewnątrz funkcji, plecenie thrw spwduje przerwanie wyknania tej funkcji i przejście sterwania d miejsca, gdzie funkcja była wywłana. 2) Jeżeli była wywłana wewnątrz innej funkcji, ta również zstanie przerwana, itd. Przerwania i przejścia sterwania w górę będą następwały aż djdą d funkcji main 3) Funkcja main również zstanie przerwana a prgram zakńczy swje działanie wyświetlając kmunikat, że zstał przerwany z pwdu wyrzucenia wyjątku. T bardz niedsknała bsługa sytuacji błędnej 72 73 Aby prgram nie przerwał swjeg działania, należy w nim zawrzeć ddatkwe instrukcje pzwalające na przechwycenie wyjątku w prgramie, tj.: Należy 1) pinfrmwać kmpilatr, w jakim bszarze kdu prgramu któraklwiek z instrukcji teg kdu mże spwdwać rzucenie wyjątku, raz 2) umieścić pd tym bszarem instrukcje przechwytujące. D znakwania sekcji kdu, w której mże wystąpić wyjątek, służy instrukcja try. // tutaj różne instrukcje naszeg prgramu Jeżeli w ciele funkcji znajduje się blk try, wewnątrz któreg zstał rzucny wyjątek, funkcja nie zstanie przerwana, tj. sterwanie nie puści tej funkcji, ale zstanie przeniesine tylk na kniec teg blku try, d pierwszej instrukcji za tym blkiem. 74 75 6
Raz rzucny wyjątek musi gdzieś trafić. Jeżeli prgramista nie przewidział miejsca bsługi, prgram zstanie zatrzymany a wyjątek bsłużny przez system peracyjny. Nrmalnym miejscem bsługi wyjątku jest prcedura, umieszczna zaraz za blkiem try Dlateg bezpśredni za kńcem teg blku, jeżeli chcemy, mżemy umieścić kawałek kdu, który wykna dpwiednie czynnści, właściwe dla klicznści, w których zaszła sytuacja błędna. Taka czynnść nazywana jest bsługą wyjątku. Obsługa wyjątku prcedura ma nazwę catch i jeden argument wywłania, którym jest biekt kreślneg typu zgdneg z typem biektu reprezentująceg wyjątek: // Kd, który mże generwać wyjątki catch (typ1 id1) { // bsługa wyjątku typu typ1 catch (typ2 id2) { // bsługa wyjątku typu typ2 76 77 class Pdgladanie { public: Pdgladanie() { cut << "Pdgladanie()"<< endl; ~Pdgladanie() { cut << "~Pdgladanie()"<< endl; ; vid przezdziurkeodklucza() { Pdgladanie P; fr(int i = 0; i < 3; i++) cut <<"Nic nie widzę."<< endl; thrw 47; cut << I c? widzisz cś?..." << endl; przezdziurkeodklucza(); catch(int) { cut << T daj też ppatrzeć." << endl; W którym mmencie zstanie wyknany destruktr klasy Pdgladanie? Obsługa wyjątku Aby dpaswać wyjątek d prcedury bsługi, nie musi istnieć dkładna zgdnść wyjątku i prcedury g bsługującej. Obiekt (lub referencja d biektu) klasy pchdnej pasują d prcedury dtyczącej klasy bazwej. W przypadku biektu dchdzi jedynie d bcięcia biektu d typu bazweg składwe ddane w klasie pchdnej nie są dstępne Z teg pwdu, a także aby uniknąć kpiwania biektów lepiej jest używać referencji d biektów. 78 79 Obsługa wyjątku Jeżeli.. w ciele funkcji żaden z typów zadeklarwanych we frazach catch nie pasuje d rzucneg biektu-wyjątku t.. sterwanie przensi się d miejsca, gdzie funkcja zstała wywłana i tam szuka sekcji try-catch. A jeżeli takiej tam nie ma, lub typy wyjątków we frazach catch nie pasują, t sterwanie dalej wędruje w górę w hierarchii wywłań funkcji w pszukiwaniu frazy catch z pasującym typem danych Sekcje try-catch mgą być zagnieżdżne dpwiedni d hierarchii wywłań funkcji. class Brzskwinia { public: class Pestka {; class Mala : public Pestka {; class Duza : public Pestka {; vid scisk() { thrw Duza(); ; Brzskwinia b; b.scisk(); catch(brzskwinia::mala&) { // nigdy nie zstanie wywłany.. cut << "Mala Pestka schwytana" << endl; catch(brzskwinia::duza&) { //.. a ten tak. cut << "Duza Pestka schwytana" << endl; catch(brzskwinia::pestka&) { // ten jest tylk pr frma. cut << " Pestka schwytana" << endl; ; 80 81 7