再學C++ ─ I/O streams 篇

幾乎所有的內容都從 “Data Structure and Programming Prof. Chung-Yang (Ric) Huang” 取得

Formatted und Unformatted

Unformatted I/O (Low-level)

  • get, getline, put, read, write…
  • high-speed, high-volume
  • may have portability problem

Formatted I/O (High-level)

  • operators “<<“ and “>>”, I/O manipulators
  • bytes are grouped into meaningful units (e.g. integer, float and character…), and sensitive to data types
  • If unexpected data is processed, error bits are set
  • ostream& operator << Does not print out until ‘\n” or “flush()” is called
  • istream& operator >> Stop at white space, but not process until ‘\n’ is entered

Unformatted I/O operation

istream::get

single characterint get();
istream& get (char& c);
c-stringistream& get (char* s, streamsize n);
istream& get (char* s, streamsize n, char delim);
stream bufferistream& get (streambuf& sb);
istream& get (streambuf& sb, char delim);

Delimiter is left in the stream, not placed in array.
Won’t process if char in stream is not enough for “streamsize”

istream::getline

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

Their has another function std::getline (string)
Delimiter is removed from the stream, and not placed in the array

istream::read

istream& read (char* s, streamsize n);

This function simply copies a block of data, without checking its contents nor appending a null character at the end.

istream::gcount

number of characters extracted by the last unformatted input operation 
(e.g. getgetlineignorepeekreadreadsomeputback and unget.)

ostream::put

ostream& put (char c);

Returns a reference to the same ostream object

ostream::write

ostream& write (const char* s, streamsize n);

This function simply copies a block of data, without checking its contents: The array may contain null characters, which are also copied without stopping the copying process.

I/O Stream Manipulators

Manipulators

dec, endl, ends, flush, hex, oct, left, right, ws, setbase(n), setw(n), setioflags(i), resetioflags(i), setfill(c), setprecision(n)

Sticky und non-sticky

“Sticky”: Not across to another object of the same stream class, or any other object of other stream classes
Most IO manipulators are “sticky”
Exception: Field width

  • setw(int) // c.f. “width()” member function
  • For both istream (input size) and ostream (display size)

I/O Stream Printing Format

  • Type fmtflags is of class ios_base
  • Initial return value may differ across platforms
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main() {
    int i = 100;
    ofstream outf("ttt");
    outf << showbase << hex << i << endl;      // 0x64
    ios_base::fmtflags origFlags = outf.flags();
    outf.close();

    ifstream inf("ttt");
    inf.flags(origFlags);
    inf >> i;
    cout << setw(10) << right << i << endl;    // 100
    return 0;
}

User-Defined

class Myclass
{
    friend ostream& operator << (ostream& os, const Myclass& e);
    int data;
};
ostream& operator << (ostream& os, const Myclass& e)
{
    os << e.data;
    return os;
}
int main()
{
    Myclass m;
    cout << m << endl;
}

State Bits

  • failbit
    • Set if input data is of wrong type (format error)
    • Data still remains in stream buffer
  • badbit
    • Set if stream extraction operation fails (more serious)
  • eofbit
    • Set if the end of file is reached during stream input
    • 先把 eof 吃進去之後才會觸發,小心不要多跑一次
  • goodbit
    • ! (failbit | badbit | eofbit)

Functions

  • bool fail(), bad(), eof(), good()
    • eofbit set to true after read in eof
  • rdstate()
    • read state bits
  • clear(iostate state = ios::goodbit)
    • clear cin and set iostate
    • default argument is set state as goodbit
#include <iostream>
#include <string>
 
int main()
{
    double n;
    while( std::cout << "Please, enter a number\n" && ! (std::cin >> n) )
    {
        std::cin.clear();
        std::string line;
        std::getline(std::cin, line);
        std::cout << "I am sorry, but '" << line << "' is not a number\n";
    }
    std::cout << "Thank you for entering the number " << n << '\n';
}

std::basic_ios::operator bool (link)

operator void*() const;(until C++11)
explicit operator bool() const;(since C++11)
  • static_cast<bool>(cin)
  • while(cin >> n)
  • operator void*()                          type-casting, converted to void*
    • A a; void *p = a;
  • void* operator() ()                      operator overloading, function object
    • A a; void *p = a();
all possible combinations of ios_base::iostate flags

Sync

std::ios::tie

ostream* tie() const;                      // get
ostream* tie (ostream* tiestr);    // set and get the old one

當一個 istream 跟 ostream 綁在一起時,c++就會確保這兩個stream動作的順序是正確的,也就是說會在 “>>” 之類的等待輸入之前,先把ostream的buffer清空並輸出。
c++一開始會自動做 cin.tie( &cout );,所以之前有時候在寫online judge時會先 cin.tie(null)取消綁定,反正oj的輸入輸出順序不影響評分嘛。
另外這個函數回傳的就是該 istream 綁定的 ostream 的 pointer ,例如沒有去做變更tie的cin的*(cin.tie())就是cout喔。

std::ios_base::sync_with_stdio(false)

默認情況下 c++ stream 會跟 c stream 同步,但這樣會讓cin/cout變得很慢,所以當你不會直接用到 c 的library時,就把這個功能關掉吧

seek/tell

c++的istream維護一個input指針(seekg/tellg),而ostream則維護output指針(seekp/tellp)

istream::seekg
istream::tellg

istream& seekg (streampos pos);                                          // 設絕對位置
istream& seekg (streamoff off, ios_base::seekdir way);   // 設相對位置, 參考點
streampos tellg()

Calling this function does not alter the value returned by gcount.

seekdir

  • ios::beg – default, position relative to the beginning
  • ios::cur – relative to current position
  • ios::end – relative to the end

buffer

ios::rdbuf()

streambuf* rdbuf() const;                       // get
streambuf* rdbuf (streambuf* sb);       // set

If sb is a null pointer, the function automatically sets the badbit error state flags (which may throw an exception if member exceptions has been passed badbit).

#include <iostream>
#include <sstream>
using namespace std;
int main () {
    stringstream ss;
    streambuf *backup = cout.rdbuf();
    streambuf *psbuf = ss.rdbuf();
    ss << "Let me write something beforehand…" << endl;
    cout.rdbuf(psbuf);
    cout << "This is written to stringstream\n";
    cout.rdbuf(backup);
    cout << "Hello!!" << endl;
    cout << ss.str() << endl;
}

Random-Access Files

#include <iostream>
#include <fstream>
using namespace std;
class StudentRecord
{
    friend istream& operator >> (istream& is, StudentRecord& e);
    friend ostream& operator << (ostream& os, const StudentRecord& e);
private:
    string _id;
    string _name;
};
istream& operator >> (istream& is, StudentRecord& e){
    return (is >> e._id >> e._name);
}
ostream& operator << (ostream& os, const StudentRecord& e){
    return (os << e._id << " " << e._name);
}
int main() {
    StudentRecord rec;
    ofstream outf("studentRecord.dat");
    cin >> rec;
    outf.write(reinterpret_cast<const char *>(&rec), sizeof(StudentRecord));
    outf.close();
    cout << rec << endl;

    rec = StudentRecord();
    cout << rec << endl;

    ifstream inf("studentRecord.dat");
    inf.read(reinterpret_cast<char *>(&rec), sizeof(StudentRecord));
    cout << rec << endl;
}
00000000: 90cd eadf ff7f 0000 0900 0000 0000 0000  ................
00000010: 6230 3736 3131 3031 3200 eadf ff7f 0000  b07611012.......
00000020: b0cd eadf ff7f 0000 0600 0000 0000 0000  ................
00000030: 616e 6472 6577 0000 0a77 bac9 517f 0000  andrew...w..Q...

Leave a Reply

Your email address will not be published. Required fields are marked *