420 likes | 623 Views
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.
E N D
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); // correct printf("%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); // correct scanf("%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 buffer cout.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 • wostream& operator<<(wostream& os, VARIANT const& arg){ • CComVariant var(arg);// Lager en kopi vi kan endre • os << L"(";// Skriver ut ’(’ på begynnelsen • if ( var.vt & VT_ARRAY ) { // Kaller ny funk. for array • PrintArray(var.vt, var.parray, os); • } else if ( var.vt == VT_RECORD ) { • PrintRecord(var, 0, os);// Kall ny funk for record • } else if (FAILED(var.ChangeType(VT_BSTR))){ • os << L"<nonprintable>";// Ingen behandling • } else if ( var.bstr == NULL ) { • os << _T(”’’”); // Tom streng • } else { // Vi har nå konvertert verdien til en bstring • os << L"'" << var.bstr << L"'"; • } • os << _T(" [") << VarTypeToString(arg.vt) << _T("])"); • return os; • }
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: Format struct 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 vellykket os << lpBuf; LocalFree(lpBuf); } else { // FormatMessage feilet os << "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”
ostream& 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; returnos; } // Bruk os << 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; Eksempel: GetLastError
Input Bruk av operator>>
Input: Eksempel string 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øring Input a string : hello Input a number : 234 Input a float : 200 String = 'hello', number = 234, double = 200 // Glemte å vente på tur Input a string : hello 235 23002.2 Input a number : Input a float : String = 'hello', number = 235, double = 23002. 2 // Ting går feil: Input a string : hello there Input 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 2 string 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øring Input a string : hello there Input 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 operatorer istream& 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() == ']' ) returnis; // Tom liste // les elementer til vi finner avslutning ']' while ( is.good() && delim != ']' ) { int current = 0; is >> current >> delim; v.push_back(current); } returnis; }
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 tm inlineostream& 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; } inlineistream& 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> classtee_streambuf : public std::basic_streambuf<char_type> { public: virtualint_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
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
classtdebugstreambuf : publicstd::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 flushed virtualint_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 buffer virtual int sync() { ::OutputDebugString(m_buffer); setp(m_buffer, m_buffer, m_buffer+nBufSize-1); return 0; } TCHAR m_buffer[BUFFER_SIZE];// The buffer }; Kildekode: tdebugstreambuf
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