strumienie, studia, Podstawy Programowania, Laboratoria


STRUMIENIE

Mimo iż język C++ pozwala korzystać ze wszystkich funkcji wejścia/wyjścia języka C, jednak definiuje także własny, zorientowany obiektowo system wejścia/wyjścia, mający postać biblioteki klas.

Standardowe wejście zapewnia odbieranie danych pochodzących z urządzeń czy plików. W tym przypadku, domyślnym źródłem strumienia danych jest klawiatura.

Zatem, wejściowy strumień danych nazywać się będzie standardowym wejściem, natomiast wyjściowy strumień danych standardowym wyjściem.

Język C ma jeden z najbardziej uniwersalnych, a jednocześnie efektywnych systemów wejścia/wyjścia. Pomimo wszystkich jego zalet, system ten nie zawiera jednak mechanizmów umożliwiających tworzenie obiektów zdefiniowanych przez użytkownika. Właśnie z ego powodu w języku C++ zostały oddzielne funkcje wejścia/wyjścia. Na przykład w języku C można zdefiniować następującą strukturę:

Informacje wymagane przez system wejścia/wyjścia języka C++ znajdują się w pliku nagłówkowym iostream.h. W tym pliku zdefiniowane są dwie struktury hierarchiczne klas, wykorzystywane przez poszczególne operacje.

Klasy biblioteki iostream.h postrzegają przepływ danych z programu na ekran jako strumień, płynący bajt po bajcie. Jeśli punktem docelowym strumienia jest plik lub ekran, wtedy źródłem jest zwykle jakaś część programu. Gdy strumień jest odwrócony, dane mogą pochodzić z klawiatury lub z dysku i mogą „wypełniać” zmienne w programie.

Jednym z podstawowych zadań strumieni jest kapsułkowanie problemu pobierania danych z wejścia (na przykład dysku) i wysyłania ich do wyjścia (na przykład na ekran).

Buforowanie

Zapis danych na dysku lub ich odczyt z dysku zajmuje dużo czasu, a podczas operacji zapisu i odczytu działanie programu jest zablokowane. Aby rozwiązać ten problem, strumienie oferują „buforowanie”. Dane są zapisywane do strumienia, ale nie są zapisywane natychmiast na dysk. Zamiast tego bufor strumienia wypełnia się danymi; gdy się całkowicie wypełni, dane są zapisywane na dysk w ramach pojedynczej operacji.

W języku C++ strumienie i bufory traktowane są w sposób obiektowy:

Gdy program C++, zawierający klasę iostream, rozpoczyna działanie, tworzy i inicjalizuje cztery obiekty (Biblioteka klasy iostream jest dodawana przez kompilator do programu automatycznie. Aby użyć jej funkcji, należy dołączyć do początku kodu swojego programu odpowiednią instrukcję #include<iostream.h>):

Tworzenie inserterów i ekstraktorów

Język C++ umożliwia wykonywanie operacji wejścia/wyjścia na klasach przez przeładowanie operatorów << i >>.

Operator << nosi nazwę operatora wstawiania (ang. insertion operator), ponieważ wstawia on znaki do strumienia. Podobnie, operator >> nosi nazwę operatora wydobywania (ang. extraction operator), gdyż wydobywa on znaki ze strumienia. Funkcje przeładowujące operatory wstawiania i wydobywania są powszechnie nazywane inserterami i ekstraktorami. Są one już przeładowane w pliku iostream.h, aby umożliwić wykonywanie strumieniowych operacji wejścia/wyjścia na wbudowanych typach danych.

Wejście z użyciem cin

Każdy ekstraktor musi zwracać odwołanie do obiektu typu istream. Również pierwszy parametr musi być odwołaniem do tego typu. Natomiast drugi parametr powinien być odwołaniem do zmiennej, do której mają zostać wpisane wprowadzone dane. Dzięki temu, że jest on odwołaniem, ekstraktor może go zmodyfikować.

Ogólna postać ekstraktora wygląda następująco:

istream &operator>>(istream &strumień, klasa &obiekt)

{

//instrukcje specyficzne dla danej klasy

return łańcuch; //zwrócenie odwołania do strumienia

}

Obiekt cin odpowiada za wejście i jest dostępny dla programu po dołączeniu biblioteki iostream.

Program: Użycie obiektu cin cin.cpp

#pragma hdrstop

#pragma argsused

#include<iostream.h>

#include<conio.h>

#include<stdio.h>

using namespace std;

int main()

{

int myInt;

long myLong;

double myDouble;

float myFloat;

unsigned int myUnsigned;

cout<<"int:";

cin>>myInt;

cout<<"long:";

cin>>myLong;

cout<<"double:";

cin>>myDouble;

cout<<"float:";

cin>>myFloat;

cout<<"unsigned:";

cin>>myUnsigned;

cout<<"\n\nint:\t"<<myInt<<endl;

cout<<"long:\t"<<myLong<<endl;

cout<<"doudle:\t"<<myDouble<<endl;

cout<<"float:\t"<<myFloat<<endl;

cout<<"unsigned:\t"<<myUnsigned<<endl;

getch();

return 0;

}

Łańcuchy

Obiekt cin może także obsługiwać argumenty w postaci łańcuchów do znaków (char*); tak więc można stworzyć bufor znaków i użyć cin do jego wypełnienia.

Jeżeli naszą zmienną uzupełniamy znakami i ostatnim znakiem jest null- wówczas cin kończy automatycznie na nim łańcuch, dlatego w buforze musi być wystarczająca ilość miejsca na pomieszczenie całego łańcucha oraz kończącego znaku null. Dla funkcji biblioteki standardowej znak null oznacza koniec łańcucha.

Obiekt cin ma jednak wady, próbując wpisać do łańcucha swoje pełne imię i nazwisko napotykamy problemy, ponieważ obiekt cin traktuje spacje lub znak nowej linii jako separatory, zakłada, że dane wejściowe są kompletne i w przypadku łańcuchów, dodaje na ich końcu znak null.

program wadycin.cpp

#include<conio.h>

#include<stdio.h>

#pragma hdrstop

#include<iostream.h>

#pragma argsused

int main()

{

char TwojeImie[50];

std::cout<<"Podaj imie:";

std::cin>>TwojeImie;

std::cout<<"Masz na imie:"<<TwojeImie<<std::endl;

std::cout<<"Podaj imie i nazwisko:";

std::cin>>TwojeImie;

std::cout<<"Nazywasz sie:"<<TwojeImie<<std::endl;

getch();

return 0;

}

Wyjście przez cout

Język C++ umożliwia bardzo proste tworzenie inserterów samodzielnie definiowanych klas.

Ogólna postać insertera wygląda następująco:

ostream &operator<<(ostream &strumień, klasa &obiekt)

{

//instrukcje specyficzne dla danej klasy

return łańcuch; //zwrócenie odwołania do strumienia

}

Właściwe zadanie wykonywane przez insertera zależy od programisty. Jedynym warunkiem stawianym przez język C++ jest konieczność zwrócenia parametru łańcuch. Całkowicie poprawne jest deklarowanie parametru obiekt jako odwołania do obiektu, a nie samego obiektu.

Stosowanie manipulatorów

System wejścia/wyjścia języka C++ udostępnia stosowanie specjalnych funkcji zwanych manipulatorami, które można umieszczać we wprowadzanych i wyprowadzanych wyrażeniach, używa się ich w celu zmiany parametrów sformatowania strumieni. Warunkiem korzystania z manipulatorów pobierających argumenty jest włączenia do programu pliku nagłówkowego iomanip.h.

Manipulatory są używane z obiektem cout.

Manipulatory, które nie wymagają pliku iomanip:

Manipulator

cel

wejście/wyjście

Dec

wprowadzanie i wyprowadzanie liczb w systemie dziesiętnym

wejście i wyjście

Endl

wyprowadzanie znaku nowego wiersza i wymycie strumienia

wyjście

Ends

wyprowadzenie znaku zerowego

wyjście

Flush

wymycie strumienia, zrzuca bufor wyjściowy

wyjście

Hex

wprowadzanie i wyprowadzanie liczb w systemie szesnastkowym

wejście i wyjście

Oct

wprowadzanie i wyprowadzanie liczb w systemie ósemkowym

wejście i wyjście

resetiosflagf(long )

wyzerowanie flag określonych w parametrze 

wejście i wyjście

setbase(int base)

ustawienie systemu liczenia o podstawie base

wyjście

setfill(int ch)

ustawienie znaku wypełnienia o kodzie ch

wyjście

setiosflags(long )

ustawienie flag określonych w parametrze 

wejście i wyjście

setprecision(int p)

ustawienie liczby cyfr po kropce dziesiętnej na p

wyjście

setw(int w)

ustawienie szerokości pola na w

wyjście

Ws

pominięcie początkowych odstępów

wejście

Manipulatory mogą należeć do wejścia/wyjścia.

Program pokazuje zmianę formatu wyprowadzania danych przez zastosowanie manipulatorów: setiosflags, setprecision i setw.

program setiosflags.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<iomanip.h>

int main()

{

cout<<setiosflags(ios::fixed);

cout<<setprecision(2)<<1000.243<<endl;

cout<<setw(25)<<"Witamy wszystkich.";

getch();

return 0;

}

Można tworzyć własne manipulatory. Dzielą się one na dwie kategorie: pobierające argumenty i nie pobierające argumentów. Między sposobami ich tworzenia istnieją drobne różnice.

Szkielet wszystkich manipulatorów wyjścia bez parametrów wygląda następująco:

ostream &nazwa_manip(ostream &strumień)

{

//instrukcje manipulatora

return strumień;

}

Program tworzy manipulator o nazwie setup(), który powoduje wyrównanie tekstu do lewej strony, ustawia szerokość pola na 10 znaków i zmienia znak wypełnienia na znak dolara :

program setup.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<iomanip.h>

ostream &setup(ostream &stream)

{

stream.setf(ios::left);

stream<<setw(10)<<setfill('$');

return stream;

}

int main()

{

cout<<""<<setup<<10;

getch();

return 0;

}

Ogólna postać wszystkich manipulatorów wejścia bez parametrów wygląda następująco:

istream &nazwa_manip(istream &strumień)

{

//instrukcje manipulatora

return strumień;

}

Program tworzy manipulator prompt(), który wyświetla tekst i przekształca wprowadzoną liczbę do postaci szesnastkowej:

program promet.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<iomanip.h>

istream &prompt(istream &stream)

{

cin>>hex;

cout<<"Wprowadz liczbe szesnastkowa:";

return stream;

}

int main()

{

int i;

cin>>prompt>>i;

cout<<i;

getch();

return 0;

}

Tworzenia manipulatora pobierającego argument nie jest już takie proste. Wynika to z faktu, że manipulatory z parametrami korzystają z klas ogólnych. Klasy ogólne tworzy się z zastosowaniem słowa kluczowego template.

W celu utworzenia manipulatora z parametrem konieczne jest włączenia do programu pliku nagłówkowego iomanip.h (zawiera on definicje m.in. klas omanip (do tworzenia manipulatorów wyjścia) oraz imanip ( manipulatorów wejścia)).

Ogólna postać manipulatorów wyjścia z parametrami jest następująca:

ostream &nazwa_manip(ostream &strumień, typ param)

{

//instrukcje manipulatora

return strumień;

}

Formatowanie danych z użyciem funkcji składowych klasy ios

Definiowanie formatu informacji wyświetlanych na ekranie, np. przez podanie szerokości pola czy określenie sposobu wyrównania danych, czyli działania, na które pozwalała nam funkcja printrf(), można wykonać korzystając z systemu wejścia/wyjścia języka C++ . Formatowanie danych wyjściowych za pomocą funkcji składowych klasy ios, to drugi sposób obok korzystania z manipulatorów.

W pliku nagłówkowym iostream.h zdefiniowane są tzw. flagi formatowania:

ios::left - wyrównuje wynik do lewej

ios::right - wyrównuje wynik do prawej

ios::internal - znak lub przedrostek zostaje wyrównany do lewej, a liczba do prawej

ios::dec - dziesiętny system liczbowy

ios::oct - ósemkowy system liczbowy

ios::hex - szesnastkowy system liczbowy

ios::showbase - dodaje przedrostek 0x do liczb szesnastkowych i przedrostek 0 do liczb ósemkowych

ios::showpoint - dodaje zera końcowe, zgodnie z wymaganą dokładnością

ios::uppercase - litery w liczbach szesnastkowych i w wartościach wyświetlanych w zapisie wykładniczym są wyświetlane jako wielkie

ios::showpos - przed wartościami dodatnimi wyświetlany jest znak plus

ios::scientific - liczby zmiennoprzecinkowe są wyświetlane w zapisie wykładniczym

ios::fixed - liczby zmiennoprzecinkowe są wyświetlane w zapisie dziesiętnym

Funkcja setf()

Obiekt iostream pamięta swój stan dzięki przechowywanym znacznikom. Można je wywołać wykorzystując funkcję setf() i przekazując jej jedną z predefiniowanych stałych wyliczeniowych. Obiekty posiadają stan wtedy, gdy któraś lub wszystkie z ich danych reprezentują warunki, które mogą ulegać zmianom podczas działania programu. Znaczniki klasy ios mogą być dodatkowo stosowane z manipulatorami

Program:

program set.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<iomanip.h>

using namespace std;

int main()

{

const int number=185;

cout<<"Liczba to"<<number<<endl;

cout<<"Liczba to"<<hex<<number<<endl;

cout.setf(ios::showbase);

cout<<"Liczba to"<<hex<<number<<endl;

cout<<"Liczba to";

cout.width(10);

cout<<hex<<number<<endl;

cout<<"Liczba to";

cout.width(10);

cout.setf(ios::left);

cout<<hex<<number<<endl;

cout<<"Liczba to";

cout.width(10);

cout.setf(ios::internal);

cout<<hex<<number<<endl;

cout<<"Liczba to:"<<setw(10)<<hex<<number<<endl;

getch();

return 0;

}

Program: setf.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

int main()

{

cout.setf(ios::showpos);

cout.setf(ios::scientific);

cout<<123<<""<<123.23<<"";

getch();

return 0;

}

Powyższy program wyświetla dane w następującym formacie:

+123 +1.232300e+02

Aby wyzerować flagi, należy skorzystać z funkcji unsetf(). Czasami potrzebna jest znajomość aktualnego stanu flag. Można go uzyskać przez wywołanie funkcji flags(): unsetflags.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

void showflags (long f);

int main()

{

long f;

f=cout.flags();

showflags(f);

cout.setf(ios::showpos);

cout.setf(ios::scientific);

f=cout.flags();

showflags(f);

cout.unsetf(ios::scientific);

f=cout.flags();

showflags(f);

getch();

return 0;

}

void showflags(long f)

{

long i;

for(i=0x8000;i;i=i>>1)

if(i&f)cout<<"1";

else cout <<"0";

cout<<"\n";

}

System wejścia/wyjścia języka C++ pozwala nie tylko korzystać z flag formatowania, ale także określać szerokość pola strumienia, znak wypełniający i liczbę cyfr wyświetlanych za kropką dziesiętną. Działania te są wykonywane za pomocą funkcji:

int width(int len);

char fill(char ch);

int precision(int num);

Program pokazujący wykorzystanie w/w funkcji: width.cpp

#pragma hdrstop

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#pragma argsused

int main()

{

cout.setf(ios::showpos);

cout.setf(ios::scientific);

cout<<123<<""<<123.23<<"\n";

cout.precision(2);

cout.width(10);

cout<<123<<""<<123.23<<"\n";

cout.fill('#');

cout.width(10);

cout<<123<<""<<123.23;

getch();

return 0;

}

Operacje wejścia/wyjścia przeprowadzane na plikach

Systemu wejścia/wyjścia języka C++ można także używać w celu operacji na plikach. Mimo, iż uzyskuje się ten sam wynik końcowy co w przypadku stosowania standardu ANSI C, to jednak między tymi dwoma metodami istnieją różnice.

W języku C++ plik otwiera się przez połączenie go ze strumieniem. Istnieją trzy typy strumieni: wejściowe, wyjściowe i wejściowo-wyjściowe. Aby otworzyć strumień wejściowy, należy go zadeklarować jako obiekt klasy ifstream. Strumienie wyjściowe są obiektami klasy ofstream, natomiast strumienie, na których będą wykonywane zarówno operacje wejścia i wyjścia , obiektami klasy fstream.

ifstream in; // wejście

ofstream out; // wyjście

fstream both; // wejście i wyjście

Jeżeli strumień został utworzony, to jednym ze sposobów połączenia go z plikiem polega na wywołaniu funkcji open(), będącej funkcją składową wszystkich trzech klas strumieni.

ios::app - powoduje dołączenie wyprowadzanych danych na koniec pliku

ios::ate - powoduje, że wskaźnik otwieranego pliku zostaje ustawiony na jego końcu

ios::binary -

ios::in - umożliwia otwieranie pliku w trybie wejściowym

ios::nocreplace - to działanie funkcji open() kończy się błędem, jeżeli określony plik nie istnieje

ios::noreplace - jeżeli została podana ta wartość (i nie zostały podane wartości ios::app i ios::ate), to funkcja open() nie otworzy pliku, który już istnieje.

ios::out - umożliwia otwieranie pliku w trybie wyjściowym

ios::trunc - funkcja open() usuwa zawartość istniejących plików.

Otwieranie pliku w trybie wyjściowym:

Np:

ofstream out;

out.open(“test”, ios::out, 0);

Otwieranie pliku w trybie wejściowym:

Np.

ifstream mystream(“myfile”);

Aby otworzyć strumień w trybie wejściowo-wyjściowym, należy podać jednocześnie wartość ios::in i ios::out.

Odczytywanie i zapisywanie plików tekstowych

Aby odczytać dane z pliku tekstowego lub zapisać dane do takiego pliku, należy po prostu użyć operatorów << i >> z otwartym strumieniem.

Program zapisuje liczbę całkowitą i zmiennoprzecinkową oraz łańcuch w pliku TEST:

zapisywaniepliku.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<fstream.h>

int main()

{

ofstream out("test");

if(!out)

{

cout<<"Blad otwarcia pliku.\n";

getch();

return 1;

}

out<<10<<""<<123.23<<"\n";

out<<"To jest krotki plik tekstowy.\n";

out.close();

getch();

return 0;

}

Program, który z pliku utworzonego w poprzednim programie wczytuje liczbę całkowitą i zmiennoprzecinkową, znak oraz łańcuch:

odczytywaniepliku.cpp

#pragma hdrstop

#pragma argsused

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<fstream.h>

int main()

{

char ch;

int i;

float f;

char str[80];

ifstream in("test");

if(!in)

{

cout<<"Blad otwarcia pliku.\n";

return 1;

}

in>>i;

in>>f;

in>>ch;

in>>str;

cout<<i<<""<<f<<""<<ch<<"\n";

cout<<str;

in.close();

getch();

return 0;

}

Operacje binarne

Niektóre systemy operacyjne, takie jak DOS, dokonują rozróżnienia pomiędzy plikami tekstowymi a binarnymi. Pliki tekstowe przechowują wszystko jako tekst (np. liczbę 54 325 przechowują jako łańcuch cyfr(`5','4','3','2','5')nieefektywne, pozwala jednak na odczyt przez proste programy. Aby odróżnić plik tekstowy od binarnego język C++ udostępnia znacznik ios::binary. Pliki binarne mogą przechowywać nie tylko liczby i łańcuchy, ale także całe struktury danych.

Można do nich zapisywać i odczytywać wszystkie dane jednocześnie, używając funkcji składowych write() i read() klasy fstream.

Funkcja write() działa podobnie jak operator wstawienia (<<), ale przyjmuje parametr określający maksymalną ilość znaków, jaka może zostać wypisana.

Program:

#pragma hdrstop

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#include<string.h>

#pragma argsused

using namespace std;

int main()

{

char One[]="Litwo Ojczyzno moja";

int fullLength=strlen(One);

int tooShort=fullLength -4;

int tooLong=fullLength +6;

cout.write(One,fullLength)<<"\n";

cout.write(One,tooShort)<<"\n";

cout.write(One,tooLong)<<"\n";

getch();

return 0;

}

Drugim sposobem zapisywania i odczytywania danych binarnych jest stosownie metody z użyciem funkcji put() i get().

Program: write.cpp

#pragma hdrstop

#include<stdio.h>

#include<conio.h>

#include<iostream.h>

#pragma argsused

int main()

{

std::cout.put('c').put('z').put('e').put('s').put('c').put('\n');

getch();

return 0;

}

Funkcja składowa get() służy do pobierania pojedynczego znaku ze standardowego wejścia, może zostać wywołana bez parametrów (zwraca ona odczytany znak lub znak EOF (znak końca pliku- end of file) w chwili dojścia do końca pliku), bądź z parametrem.

Program użycia funkcji get() bez parametrów: getbezparametrow.cpp

#pragma hdrstop

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#pragma argsused

int main()

{

char ch;

while((ch=std::cin.get())!=EOF)

{

std::cout<<"ch:"<<ch<<std::endl;

}

std::cout<<"\nGotowe!\n";

getch();

return 0;

}

Program użycia funkcji get() z parametrem: getzparametrem.cpp

#pragma hdrstop

#include<conio.h>

#include<stdio.h>

#include<iostream.h>

#pragma argsused

int main()

{

char a,b,c;

std::cout<<"Wpisz trzy litery:";

std::cin.get(a).get(b).get(c);

std::cout<<"a:"<<a<<"\nb:";

std::cout<<b<<"\nc:"<<c<<std::endl;

getch();

return 0;

}



Wyszukiwarka

Podobne podstrony:
PP1, Informatyka - studia, Podstawy programowania, semestr III
Podstawy programowania Laboratorium 1
Podstawy programowania Laboratorium 2
11-nkb~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
1-algo~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
c-zadania-w3, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, kol
Laboratorium Podstaw Programowania 2
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
x, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, kol 1
minmax3, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l6
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
c klasowka1 rozwiazania, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programo
pp projekty2004, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania
PODSTAWA PROGRAMOWA WYCHOWANIA PRZEDSZKOLNEGO, STUDIA

więcej podobnych podstron