Streamy
Vstup a výstup – streamy – přepište programy na tisk tabulek (cvičení č.1/ příklad 2) za pomoci možností jazyka C++ (streamy). Zkuste provést výstup na standardní výstup (cout) a do souboru. Procvičte si formátování na nastavení šířky (oba způsoby – width, setw), nastavení výplňového znaku (oba způsoby), zarovnání vlevo a vpravo.
Prostory jmen (při použití cout, cin si vyzkoušejte použití std::cout, cout s using std::cout, using namespace std a promyslete výhody a nevýhody)
Podrobný návod na zkoušení vlastností streamů
založte si prázdnou konzolovou aplikaci a v ní vytvořte jeden zdrojový soubor s funkcí main
ve funkci main zavolejte první testovací funkci pro zkoušení tisku na konzolu
vyzkoušejte si jednoduchý tisk (textu “ahoj z bppc“) přes streamy. K tisku použijte objekt pro tisk na konzolu cout. K jeho použití potřebujete naincludovat příslušnou knihovnu (iostream) a vyřešit zpřístupnění proměnné, která se nachází ve jmenném prostrou std
K ovládání streamů je možné použít metody, nebo speciální „funkce“ manipulátory. Tyto se vkládájí mezi „vystupující“ proměnné, které jsou během tisku zavolány a slouží k činnosti spojené s prací streamu (například nastavení proměnných streamu, vykonání určité činnosti …). Často používanou činností je například odskok na nový řádek – k tomu je možné použít standardně cout << “\n“ ale je možné použít manipulátor cout << endl; , který vyšle znak nový řádek a ještě provede flush (což je další manipulátor – pro „vysypání“ bufferu. Většina streamů má mezi uživatelem a zařízením vyrovnávací buffery, ve kterých se data shromažďují aby se ze zařízením pracovalo efektivně, tj. po větších celcích dat. Proto je někdy nutné říci, že teď je okamžik, kdy se mají data přepsat fyzicky do zařízení).
Podobně funguje načítání, které je realizováno pomocí vstupních streamů a „předvytvořeného“ streamu/objektu pro klávesnici. Ten se jmenuje cin. Jelikož je využito vlastnosti přetěžování, poznají objekty streamu typ se kterým pracují a vstup a výstup jsou tedy typově orientované (uživatel se nemusí starat o spojení proměnné s načítaným typem – stále ale platí, že při vstupu musí přijít řetězec, který je převoditelný/interpretovatelný na typ, kterého je proměnné do které se načítá. Zkuste načíst dvě čísla do celočíselných proměnných. Tyto dvě čísla vytiskněte na obrazovku a společně s nimi jejich podíl v plovoucí řádové čárce (nepoužívejte však žádnou další/pomocnou proměnnou)
Vytiskněte (formátovanou, zarovnanou) tabulku malé násobilky
(podobně jako na jednom z prvních cvičení). Pro nastavení šířky
tisku je možné použít buď metodu streamu (cout.width(4)) nebo
manipulátor (<<setw(4)<<). Tyto vlastnosti mají
vlastní knihovnu (iomanip). Zkuste zjistit, jaká je defaultní
hodnota šířky pole pro tisk.
Některá z nastavení mají za
následek trvalé změny, některé se po prvním/následujícím tisku
nastaví do defaultní hodnoty.
Většina metod funguje tak, že
nastaví příslušnou proměnnou podle předávaného parametru (je-li
nějaký) a vrátí původní hodnotu.
Následně zkuste vytisknout tabulku malé násobilky (celých
čísel) v šestnáctkové soustavě. Pro nastavení soustavy existuje
trojice bitů, které ji ovlivňují – oct, dec, hex. Je
tedy možné vložit příslušné manipulátory, které přepnou „soustavu“
tisku, přímo do streamu. Tyto bity jsou součástí příznaků nastavení
(flags) a je možné je nastavovat i přímo. K nastavování
příznaků slouží metoda setf, která zavádí nový koncept. Z
důvodu bezpečnosti (aby z příslušné n-tice bitů byl nastaven vždy
jen jeden) má tato metoda dva parametry – první parametr
určuje vlastnost (bit) a druhý skupinu (bitů) do které patří. Při
nastavování bitu je potom celá skupina nejprve vynulována a následně
je nastaven (pouze jeden) bit. K definici bitů slouží výčtový typ v
pomocné třídě ios_base (dříve pouze ios) – pro hex
je to ios_base::hex, a příslušná skupina je
ios_base::basefield. Out.setf(ios_base::oct,
ios_base::basefield)
(Pře)nastavování bitů sledujte pomocí
(hexa tisku) registru stavů, pro které je definován typ fmtflags
a které lze získat pomocí metody streamu setf.
Toto
nastavení je trvalé (až do další změny). Po vytisknutí hodnoty
nedojde k přenastavení do default stavu.
Obdobně můžete zkusit formátovaný tisk A*cos(w) – zde si můžete prozkoušet – setfill, setprecision, scientific …
Nyní celou tuto funkci zkuste předělat tak, aby se stream do ní dostával jako její parametr – neboli z funkce main (volání test(cout)). Zjistěte jakého typu je cout a předejte ho – ve funkci všechny výskyty cout přejmenujte na název předávané proměnné – například output_s.
Procvičte si práci se soubory pomocí streamů.
Jelikož
každá třída má svoji specializaci (u třídy pro cout, cin jsou
to specializace na konzolu – textový monitor a klávesnici) je
nutné pro práci se soubory používat jinou třídu – zde
ifstream, ofstream (knihovna fstream). Soubor
(objekt dané třídy) se vytváří (konstruktorem) pomocí dvou
parametrů, první je název souboru, druhý typ otevření. Otevřete
soubor pro zápis (ios_base::out), v textovém modu
(nenastavuje se, je defaultní, jinak ios_base::binary), a po
otevření ať se soubor nastaví na prázdný (ios_base::trunc).
Tyto nastavení je nutné bitově sečíst. (Blíže na použité flagy se
můžete podívat v hlavičce xiosbase)
ověřte, že se soubor otevřel (pomocí metody is_open).
Do souboru vložte/vytiskněte (obdobně jako do cout) proměnné následující: int, mezery, text=řetězec, mezery, int
můžete vyzkoušet s takto otevřeným streamem (ofstream) zavolat i funkci test z předchozího bodu (tisk na konzolu). Tato funkce má sice jako parametr ostream , ale protože ostream má společný základ se třídou ofstream (je jejím předkem), bude toto fungovat. Opačné volání není povoleno (pokud bu nebyla zajištěna konverze na potomka ofstream z předka ostream). Proto je lepší psát pro vlastní třídy a jejich práci se streamy metody pro parametry typu ostream (Je možné je použít jak pro výstup na konzolu tak do souboru).
nyní zkuste soubor přečíst. K tomu je dobré mít soubor neotevřený, a proto ho zavřete (metodou close). Standardně není nutné metodu close volat, protože se jedná o objekty a k zavření dojde automaticky v destruktoru při zániku objektu. Při čtení se používá třída ifstream s modem otevření in.
V otevřeném souboru zkuste načíst čtyři proměnné typu int – mezi jednotlivými čteními sledujte vývoj bitů – bad, fail, good, eof (pomocí příslušných metod – bad, fail, good, eof). Tyto metody vrací hodnoty bitů odpovídající flagům informujících o stavu streamu. Bad je hrubá chyba, kterou je těžko odstranit – například přetržený kabel. Fail je menší chyba, ze které je možné se vzpamatovat (nedošlo ke ztrátě dat) – zde například to, že druhý (a další int) se nenačtou, protože na vstupu jsou znaky/text a ne číslice. Good značí, že nedošlo k chybě a eof informuje o dosažení konce souboru (opět nastaven až v okamžiku načtení prvního znaku za koncem souboru).
Překopírujte soubor znak po znaku na obrazovku.
Nejprve musíme „oživit“ stream po chybě nastavením bitu good. Pomocí metody streamu clear a jménem nastavovaného bitu (goodbit).
Následně je nutné se vrátit na počátek souboru pomocí metody seekg, která má dva parametry. První určuje vzdálenost a druhý odkud (pro počátek souboru je ios_base::beg).
Při tisku zjistíme, že bílé znaky (mezery) jsou ignorovány. Tuto vlastnost odstraníme pomocí manipulátoru noskipws.
Poslední úpravy 2008-12-01