c++ streams

42
C++ Streams Input og Output med C++ Standard Biblioteket

Upload: claral

Post on 26-Jan-2016

40 views

Category:

Documents


1 download

DESCRIPTION

C++ Streams. Input og Output med C++ Standard Biblioteket. Sammenheng. Hva gjør Streams? Input/output Formattering av tall, datoer, etc. Utskrift av objekter Transparent håntering av forskjellige kilder Hvilken annen funksjonalitet finnes for dette? printf, wfprintfn, tsprintf, etc. - PowerPoint PPT Presentation

TRANSCRIPT

C++ Streams

Input og Outputmed

C++ Standard Biblioteket

Sammenheng

• Hva gjør Streams?– Input/output

– Formattering av tall, datoer, etc.

– Utskrift av objekter

– Transparent håntering av forskjellige kilder

• Hvilken annen funksjonalitet finnes for dette?– printf, wfprintfn, tsprintf, etc.

– strftime

– scanf

Hva gir Streams?

• Uniform håntering av argumenter• Typesikkerhet• Transparent håntering av kilde og destinasjon

– Konsol I/O– Streng– Fil– Egendefinerte (f.eks. Nettverk, eller DebugStream)

• Automatisk minnehåntering/bufferhåntering• Intergrasjon med Locales

Uniform håntering av argumenter

{MyClass obj;struct tm timeNow;char const* myString;int myNumber;

std::cout << obj << ” litt tekst ” << timeNow

<< ”mer tekst ” << myString << myNumber

<< std::endl;}

Typesikkerhet

printf("%d\n", int_variable); // correctprintf("%f\n", double_variable); // correct

printf("%d\n", double_variable); // outputting an int, but a double value is supplied

printf("%f\n", int_variable); // outputting a double, but an int value is supplied

printf(”%s\n”, string(”Hello world”));// outputting a string, but an object is supplied

scanf("%d", &int_variable); // correctscanf("%d", int_variable); // oops! left out the ampersand!

scanf("%lf", &int_variable); // oops! reading a floating-point value into an integer!

scanf(”%s”, &string_variable); // oops! reading into object

Kildeuavhengighet

• Gjøres ved hjelp av stream-buffer klasser• En istream/ostream kan assosieres med en vilkårlig

stream-buffer klasse• Dersom ingen buffer-klasse passer, kan man lage

sin egen• fstream- og stringstream-klassene bruker kun

constructor til å angi en fil-buffer• En streambuffer hånterer minne selv• En stream brukes på samme måte uavhengig av

buffer

Eksempel

{std::ofstream logFile(”LogFile.txt”);

streambuf oldBuf = cout.rdbuf(logFile.rdbuf());

// Bruk cout som normal. Output vil komme// til LogFile.txt fila

// Reset buffercout.rdbuf(oldBuf);

}

Formattering

operator<<, operator>>

Manipulatorer

Locales

operator<< og operator<<

• Operator<< brukes til å skrive ut verdier

• Operator>> brukes til å lese verdier

ofstream os(”outfile.txt”);ifstream is(”infile.txt”);

int a = 14, b = 20;string str(”Hello world”);

os << a << ” + ” << b << ” = ” << a+b << endl;os << str << endl;

is >> a >> b >> b;

Operator overloading

• << og >> er overloaded for alle argumenter vi ønsker å skrive ut

• << og >> har presendens mellom +/- og <, <=, etc– os << a + b os << (a + b), men– os << a < b (os << a) < b, som er feil

• << er venstre-assosiativ– os << a << b << c ((os << a) << b) << c

op<<(op<<(op<<(os, a), b), c)

– Dette fungerer fordi op<<(os, a) returnere en referanse til os

Definere egne operatorer

• Man kan overloaded operator<< og operator>> for å lage lesing og skriving av en klasse.

Eksempel: VARIANT

1.wostream& operator<<(wostream& os, VARIANT const& arg) {2. CComVariant var(arg); // Lager en kopi vi kan endre3. os << L"("; // Skriver ut ’(’ på begynnelsen4. 5. if ( var.vt & VT_ARRAY ) { // Kaller ny funk. for array6. PrintArray(var.vt, var.parray, os);7. } else if ( var.vt == VT_RECORD ) {8. PrintRecord(var, 0, os); // Kall ny funk for record9. } else if ( FAILED(var.ChangeType(VT_BSTR)) ){10. os << L"<nonprintable>"; // Ingen behandling11. } else if ( var.bstr == NULL ) {12. os << _T(”’’”); // Tom streng13. } else { // Vi har nå konvertert verdien til en bstring14. os << L"'" << var.bstr << L"'";15. }16. os << _T(" [") << VarTypeToString(arg.vt) << _T("])");17. return os;18.}

Manipulatorer

• I tillegg til tekst, kan man sende manipulatorer til en strøm

• Manipulatorer endrer ofte oppførsel til strømmen, eller har andre sideeffekter

• Eksempler på manipulatorer fra <iomanip>– endl – skriver ut en newline og flusher buffer– Setw, setfill – setter bredden og fill for numre– Boolalpha – skriver ”true” og ”false” for bool– Setprecision – setter presisjon for flyttall– Fixed, scientific – setter notasjon for flyttall

Output formattering

• Integers:– os << setw(4) << setfill(’0’) << 8 ”0008”

– os << setbase(16) << showbase << 2147500037 ”0x80004005” (E_FAIL)

• Bools– os << boolalpha << true ”true”– os << noboolalpha << true ”1”

• Floating points– os << scientific << 1000.0 ”1.00000e3”– os << fixed << setprecision(2) << PI ”3.14”

Manipulatorer

• Uten argumenter– En funksjon med profil ostream& f(ostream&)

er automatisk en manipulator– Eks: tostream& GetLastError(tostream& os);

• Med argumenter– Må være en klasse med args som constructor-

argumenter og operator << definert

Eksempel: Formatstruct Format // Uses FormatMessage API to decode error code{

Format(HRESULT hr) : m_hr(hr) {}

friend ostream& operator<<(ostream& os, Format const& self) {LPSTR lpBuf = 0;DWORD nRetval = FormatMessage(..., NULL, self.m_hr, 0,

(LPSTR)&lpBuf, 0, NULL);

if ( nRetval != 0 ) { // FormatMessage var vellykketos << lpBuf;LocalFree(lpBuf);

} else { // FormatMessage feiletos << "Error " << showbase << setbase(0x10) << self.m_hr <<

endl;}

return os;}

private:HRESULT m_hr;

};

cout << Format(E_NOTIMPL) << std::endl; // ”Not implemented”cout << Format(0x80041002) << std::endl; // ”Error 0x80041002”

Eksempel: GetLastErrorostream& GetLastError(ostream& os){

DWORD nStatus = ::GetLastError();if ( nStatus == 0 ) return os; // no error occured

os << "Error code : " << nStatus << ". ";os << "Error text : " << Format(nStatus) << std::endl;

return os;}

// Brukos << GetLastError << std::endl;

// Mangler med Format (finnes i WinStream.cpp i f.eks. AccountingSrv):// Må fjerne \n\r fra slutten av feiltekster// Må kunne finne feil i andre moduler:

string const oleDbModule("c:\\program files\\common files\\system””\\ole db\\msdaerr.dll”);

os << Format(hr, oleDbModule) << endl;

Input

Bruk av operator>>

Input: Eksempelstring str;cout << "Input a string : ";cin >> str;

int I = 0;cout << "Input a number : ";cin >> i;

double d = 0.0;cout << "Input a float : ";cin >> d;

os << "String = '" << str << "', number = " << i << ", double = " << d << std::endl;

// KjøringInput a string : helloInput a number : 234Input a float : 200String = 'hello', number = 234, double = 200

// Glemte å vente på turInput a string : hello 235 23002.2Input a number : Input a float : String = 'hello', number = 235, double = 23002.2

// Ting går feil:Input a string : hello thereInput a number : Input a float : String = 'hello', number = 0, double = 0

Input

• Å lese på cin flusher cout. Dette er fordi strømmene er ”tied”:– cin.tie(cout);

• Input er white-space separert, selv fra konsol– Whitespace er definert i forhold til locale.

• Dersom man skriver noe uventet, leses ikke verdien– Man kan bruke funksjonen basic_istream::good() for å

se om det gikk galt

Input streams 2string str;cout << "Input a string : ";cin >> str;

int i = 0;cout << "Input a number : ";cin >> i;if ( !cin.good() ) {

cout << "Invalid number!" << std::endl;}

double d = 0.0;cout << "Input a float : ";cin >> d;if ( !cin.good() ) {

cout << "Invalid number!" << std::endl;}

cout << "String = '" << str << "', number = " << i << ", double = " << d << std::endl;

// KjøringInput a string : hello thereInput a number : Invalid number!Input a float : Invalid number!String = 'hello', number = 0, double = 0

Input: andre funksjoner

• istream& getline(char *s, streamsize n, char delim)

• peek, ignore, putback• istream_iterator• Mer finkornete feilhånteringsfunksjonalitet

– fail (kunne ikke lese) vs. bad (buffer i en ”farlig tilstand”) vs. eof (slutt på input)

• Mer fleksibel whitespace håntering

Egne operatoreristream& operator>>(iostream& is, vector<int>& v) { // Leser en vector som ser slik ut: ”[0, 2, 5, ... ]” char delim; v.clear();

// skjekk åpningstegn is >> delim; if ( delim != '[' ) { // Dette er ikke en liste is.putback(delim); is.clear(ios::badbit|is.rdstate()); return is; }

if ( is.flags() & ios::skipws ) is >> ws; if ( is.peek() == ']' ) return is; // Tom liste

// les elementer til vi finner avslutning ']' while ( is.good() && delim != ']' ) { int current = 0; is >> current >> delim; v.push_back(current); }

return is;}

Locales

• Et locale er beskrivelse av settings for brukerens plassering i verden

• Et locale inneholder flere facets. En facet angir settings for ett aspekt med localet

• Følgende standard facet eksisterer– ctype (character egenskaper)– collate (sortering), codecvt (tegnsett konvertering)– Penger: moneypunct, money_get, money_put– Numre: numpunct, num_get, num_put– Dato: time_get, time_put– messages

Locales og strømmer

• Ios_base, som er superklasse til ostream og istream definerer funksjonene:– getloc() returner locale objektet til strømmen– imbue() setter nytt locale objekt for strømmen

• Locale-objektet brukes til å formattere tall, men kan også brukes i egendefinerte operator<<

Eksempel med struct tminline ostream& operator<<(ostream& os, struct tm& tm){

typedef time_put<char> ttimeput;

ttimeput const& timeput = _USE(os.getloc(), ttimeput);timeput.put(ttimeput::iter_type(os),os,&tm, 'x');return os;

}

inline istream& operator>>(istream& is, struct tm& tm){

typedef time_get<char> ttimeget;

ttimeget const& timeget = _USE(os.getloc(), ttimeget);timeget.get_date(ttimeput::iter_type(is.rdbuf()), timeput::iter_type(),

is, is, &tm);

if ( !is ) return is;

timeget.get_time(ttimeput::iter_type(is.rdbuf()), timeput::iter_type(), is, is, &tm);

return os;}

Streambuffer

Oversikt

Class tee_streambuf

Om overstyring av buffere Class tdebugstreambuf

Streambuffer

• Oppgaver– Hånterer kilde/destinasjon for lesing å skriving– Bufring/minnehåntering– Unicode/ANSI konverteringer

• Kan overstyres etter brukers behov• Gjør ingen formattering av output• Ganske stor og forvirrende klasse, så jeg

vil kun gi en grunnleggende oversikt

Streambuffer interface

• Input– in_avail() – input: chars som kan leses før sync– snextc() – returnerer neste character– sbumpc() – hopper en character fram– sgetc() – returnere nåværende character– sgetn(E *s, streamsize n) – leser neste n– sputbackc(E c) – angrer lesing av c– sungetc() – angrer forrige lesning

• Output– pubsync() – flusher bufferet– sputc(E c) – skriver neste char– sputn(const E *s, streamsize n)

std::basic_streambuf

• Baseklassen til alle strømbuffere• Gir en implementasjon av alle funksjonen, både

for bufret og ubufret I/O• Har to ”lag” med ”template method” patternet

– xgetn, xget, xputn – kan overstyres, men fungerer bra for de fleste formål, de kaller:

– uflow, underflow, sync og overflow, som bør overstyres

Ubufferet I/O

• En ubufferet streambuf sender I/O direkte til sin eksterne kilde

• Input: Må overstyre uflow til å returnere neste character

• Output: Må overstyre overflow til å sende characters

Eksempel: tee_streambuf

• Sender output til alle registrerte buffere

• Er ubufret (dvs. mellomlagrer ikke data)

• Overrider kun følgende metode:– Overflow

• Jeg har ikke laget kode for å manipulere bufferene som det videresendes til

tee_streambuf source:

template<class char_type>class tee_streambuf : public std::basic_streambuf<char_type>{public: virtual int_type overflow(int_type c) {

for ( Buffers::iterator pBuffer=m_listeners.begin(); pBuffer!=m_listeners.end();

++pBuffer ) {

if ( pBuffers->sputc(c) == traits_type::eof() )return traits_type::eof();

}

return traits_type::not_eof(c);}

private:typedef std::vector< std::basic_streambuf<char_type> > Buffers;Buffers m_listeners;

};

Buffer-basert Input

• Input buffer– eback(), gptr(), og egptr() angir start, current og slutt,

respektive

– setg() kan brukes til å sette disse pekerene

– gbump() brukes til å inkrementere current

• Basic_streambuf::xsgetn hånterer input til det ikke er mer igjen i bufferet, kalles underflow.

• underflow må hente mer til bufferet, eller returnere eof.

Buffer-basert output

• Output buffer:– pbase(), pptr(), epptr() angir buffer

– setp() setter buffer

– pbump() inkrementere current

• basic_streambuf::xsputn hånterer output til det ikke er mer plass i bufferet, så kalles overflow.

• overflow må skaffe mer plass, eller returnere eof• I tillegg må sync sørge for at bufferet flushes

Streambuffer implementasjon

Get Area (input) Put Area (output)

Unbuffered uflow overflow

Buffered underflow overflowsync

Buffer eback,gptr,egptr,gbump

pbase,pptr,epptr,pbump

Eksempel 2: tdebugstreambuf

• Bufret output streambuffer

• Sender output til Win32 API’et OutputDebugStream

• Fungerer kun som output

• Binder cout til seg selv, slik at cout går til debug-strømmen

Kildekode: tdebugstreambuf

class tdebugstreambuf : public std::basic_streambuf<TCHAR>{

tdebugstream() { setp(m_buffer, m_buffer, m_buffer+nBufSize-1);cin.rdbuf(this);

}// This method is called when the buffer is filled up and must be flushedvirtual int_type overflow(int_type c) {

if (traits_type::eq_int_type(traits_type::eof(), c))return traits_type::not_eof(c);

synch();sputc(traits_type::to_char_type(c));return traits_type::not_eof(c);

}// This method is called when user requests flushing of the buffervirtual int sync() {

::OutputDebugString(m_buffer);setp(m_buffer, m_buffer, m_buffer+nBufSize-1);return 0;

}

TCHAR m_buffer[BUFFER_SIZE]; // The buffer};

Bruk av tdebufstreambuf

• Lag et bufferobjekt

• Lag en basic_ostream<TCHAR>

• Send output til strømmen

tdebugstreambuf debugstreambuf;basic_ostream<TCHAR> traceStream(&debugstreambuf);

traceStream << _T(”Hello world”) << std::endl;

Bonus: Videre muligheter

• Jeg bruker i DataLayerSrv og AccountingSrv noen hjelpeklasser

• Stream-manager– Velger mellom flere strømmer avh. av oppsett– Eks. TraceMgr[TraceProgress] << ”Det går

fremover”

Stack-objekt som følger fremgang

• TraceBlock trace(”FunctionName”);– Gjør trace[TraceProgress] << functionName << ”entered”

• trace.Progress(”Doing something”);– Gjør trace[TraceProgress] << functionName << ”Doing

something”

• trace[TraceWarn] << ”Something went wrong”;• trace.NormalExit();

– Gjør trace[TraceProgress] << ”Function exited”– Dersom det ikke gjøres, vil destructor gjøre

trace[TraceWarn] << ”Abnormal termination. Last progress was ” << lastProgress;

Ressurser

• Angelica Langer & Klaus Kreft, ”Standard C++ IOStreams and Locales”, 2000, utdrag på http://www.langer.camelot.de/ IOStreams/about.htm

• IOStream Examples: http://uw7doc.sco. com/SDK_clib/CTOC-_iostream_Examples.html