C++ IO流小結


撒花慶祝下,終於看完了(C++Primer)第一部分,即將進入第二部分!

 

IO部分,最基本的是iostream(istream、ostream),子類有fstream(ifstream、ofstream)和sstream(istringstream、ostringstream)。

iostream是控制窗口輸入輸出。

fstream是文件輸入輸出。

sstream是字符串輸入輸出(內存中)。

 

如果兩種類型存在繼承關系,則可以說一個類“繼承”了其父類的行為——接口。
C++ 中所提及的父類稱為基類(base class) ,而繼承而來的類 則稱為派生類(derived class)

 
IO 類型在三個獨立的頭文件中定義:
    iostream 定義讀寫控制窗口的類型,  fstream 定義讀寫已命名文件的類型,而 sstream 所定義的類型則用於讀寫存 儲在內存中的 string 對象。
    在 fstream 和 sstream 里定義的每種類型都是從  iostream 頭文件中定義的相關類型派生而來。
wchar_t、wiostream。。。
 
IO流不允許賦值或者復制
所以,
①函數形參和返回值不能是IO流對象,必須是引用,而且形參不能是const--因為讀寫都會改變狀態。
②只有支持復制的元 素類型可以存儲在 vector 或其他容器類型里。由於流對象不能復制,因此不能 存儲在 vector (或其他)容器中 (即不存在存儲流對象的 vector 或其他容器)。

所有的流對象,都包含一個條件狀態成員,該成員由setstate clear 操作管理。該成員類型為iostate 。另外有三個常量,代表三種狀態,可進行操作。badbitfailbiteofbit
流的狀態檢查操作則有:bad、fail、eof、good。如果bad、fail、eof中任一個返回true,則流處於錯誤狀態。否則good操作返回true。
clear和setstate操作用於改變條件成員的狀態。clear會重設為有效狀態。setstate用於打開某個條件,用於表示某個問題的發生。setstate會保留其他狀態。
 
 
IO緩沖區每個io流對象都管理一個緩沖區!用於存儲程序讀寫的數據。
除了自動刷新緩沖區之外,還可以手動刷新緩沖區:endl、flush、ends。
另外,如果想讓io流刷新輸出每次讀寫的數據,可以使用 unitbuf
cout<< unitbuf<<"first"<<" second"<< nounitbuf ; //相當於cout<<"first"<< flush<<"second"<< flush ;
 
警告:如果程序崩潰了,則 不會刷新緩沖區!!    這個特性可以用來查找錯誤,只能是在最后輸出語句的后面。
 
----------------------------------
當輸入流和輸出流 到一起時,任何讀輸入流的嘗試,都將 刷新其輸出流關聯的緩沖區。
標准庫將cout和cin綁定到一起,所以,任何cin語句,都會導致cout緩沖區的刷新。
注意: 只是刷新!沒有傳遞數據!!!且一個對象只能綁定一個對象。
 
交互式系統通常應確保它們的輸入和輸出流是綁在一起的。這樣可以保證任何輸出都是在試圖讀之前進行。
cin.tie(0); //斷開默認的tie(默認cin.tie(&cout))
cin.tie(&cerr); //重新綁定
----------------------------------
 
文件操作
fstream 類型除了繼承下來的行為外,還定義了兩個自己的新操作—— open close,以及形參為要打開的文件名的構造函數。

需要讀寫文件時,則必須定義自己的對象,並將它們綁定在需要的文件上。
假設 ifile 和 ofile 是存儲希望讀寫的文件名的 strings 對象,可如下編寫代碼: 

 

// construct an ifstream and bind it to the file named ifile 
ifstream infile(ifile.c_str()); 
// ofstream output file object to write file named ofile 
ofstream outfile(ofile.c_str());

 


也可以如下編寫代碼:
ifstream infile;
ofstream outfile;
 
infile.open(ifile.c_str());
outfile.open(ofile.c_str());
 
為了實現讀寫,需要將指定的文件 打開定位open 函數完成系統指定的所有需要的操作。
 
打開文件后,檢查是否正確打開是個好習慣: if(!infile)...//如果沒打開。
 
注意:歷史原因,只能使用C風格字符串作為文件名。
 
#include <iostream>
#include <string>

using namespace std;

int main(){
    
    cout<<"endl!"<<endl;
    cout<<"flush!"<<flush;//
    cout<<"null-terminated ends!"<<ends;
    
    cout<<"\r\n";
    //一次性刷新所有輸出
    cout<<unitbuf<<"first"<<" second"<<nounitbuf; //cout<<"first"<<flush<<"second"<<flush;
    
    cout<<"\r\n";
    ///=----------------------
    ostream *old_tie = cin.tie(); 
    cout<<"old_tie:"<<old_tie<<endl;
    cin.tie(0);
    cin.tie(&cerr); //why &?
    
    cerr.tie(0);
    cerr.tie(&cout);
    
    string str;
    cin>>str;
    cerr<<"hehe";//如何不刷新? 
    cerr<<"hehe";//如何不刷新? 
    
    cin>>str;//再來一次 
    cerr<<str;
    cout<<str;
    
    return 0;
}
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(){
    string infile="abc";
    string outfile="abc";
    ifstream in(infile.c_str());
    ofstream out(outfile.c_str());
    
    if(!in){
        cerr<<"Error: unable to open file:"<<infile<<endl;
        return -1;
    }
    if(!out){
        cerr<<"Error: unable to open file:"<<outfile<<endl;
        return -1;
    }
        
    return 0;
}
//這個代碼有問題,忽略吧
#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

void run1();
void run2();
istream &getistream(istream &in);

int main(){
    run1();
//    run2();
//    
//    getistream(cin);//注意,io流不可復制或賦值。 
//    if(cin){
//        cout<<"OK!"<<endl;
//    }else{
//        cout<<"sth is wrong"<<endl;
//        if(cin.eof()){
//            cout<<"eof was not cleared!"<<endl;
//        }
//        if(cin.bad()){
//            cout<<"bad was not cleared!"<<endl;
//        }
//        if(cin.fail()){
//            cout<<"fail was not cleared!"<<endl;
//        }
//        return -1;
//    }
    
    
    return 0;
}

void run1(){
    int val;
    while(cin>>val, !cin.eof()){//有輸入,不是結尾,就繼續 。逗號運算符,返回右邊的結果 
        if(cin.bad()){
            cout<<"input stream damaged!"<<endl;
            throw runtime_error("IO stream corrupted");
        }
        if(cin.fail()){
            cerr<<"bad input!"<<endl;
//            cin.clear(istream::failbit);//
//            cin.clear();
//            cin.clear(istream::goodbit);
            cin.clear(istream::failbit);
            cin.clear(istream::badbit);
            cin.clear(istream::eofbit);
//            cin.clear();//why this does not work? 
            
//            cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
            cout<<"try again.."<<endl;
            continue;
        }
        cout<<val<<endl;
    }
}

void run2(){
    string str;
    cout<<"type sth .."<<endl;
    cin>>str;
    iostream::iostate old_state= cin.rdstate();//
    cout<<old_state<<endl;
    cin.clear();//what?
    //...
    cin.clear(old_state);//清除舊狀態,而非設置舊狀態!設置應該是setstate。這里書上弄錯了吧。 
    
}

istream &getistream(istream &in){
//    iostream::iostate old_state = in.rdstate();
    cout<<"type sth.."<<endl;
    
    string str;
    while(in>>str, !in.eof()){
        //
        if( in.fail() || in.bad()){
            cerr<<"fail or bad";
            in.clear();
            continue;
        }
        cout<<"you typed: "<<str<<endl;
    }
//    in.setstate(old_state);
//    in.clear(old_state);//for what?
    in.clear();//恢復正常 
    return in;
}

 

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;
ifstream &openfile(ifstream &in, string &filename);
ofstream &savefile(ofstream &out, string filename);

//復制文件練習 
int main(){
    string filename="e:/DbUtil.java";
    string filename2="e:/DbUtil1.java";
    ifstream in;
    ofstream out;
    openfile(in, filename);
    savefile(out,filename2);
    
    string line;
    while(getline(in, line)){
        out<<line<<endl;
    }
    in.close();
    out.close();
    
    return 0;
}

ifstream &openfile(ifstream &in, string &filename){
    in.close();
    in.clear();
    
    in.open(filename.c_str());
    
    return in;
}

ofstream &savefile(ofstream &out, string filename){
    out.close();
    out.clear();
    
    out.open(filename.c_str(),ofstream::app);
    return out;
}

 

----------------------------------
 
 
打開文件需要指定打開的mode,這是文件自身的屬性!
mode:in、out、app、ate、trunc、binary。
單純以out打開,會丟失所有內容。類似out|trunc。
fstream對象默認以in|out模式打開,不清空!!!
fstream inOut("xxx", fstream::in | fstream::out);

ate是個什么鬼?app會在每次寫操作之前都把寫指針置於文件末尾,而ate模式則只在打開時才將寫指針置於文件末尾。ate模式在文件操作過程中,可以通過seekp等操作移動指針位置。

 
------------------------------------------------
sstream,用於從內存中的字符串讀取數據,或,向內存中的字符串寫入數據!
也可以用於 格式轉換!!!其實就是通過特定類型的 變量來接收!
 
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;
ifstream &openfile(ifstream &in, string &filename);

int main(){
    string filename="e:/DbUtil.java";
    ifstream in;
    openfile(in, filename);
    
    string line, word;
    
    while(getline(in, line)){
        istringstream strin(line);
        ostringstream strout(line); 
        while(strin>>word){
            strout<<word<<endl;//輸出到string了,看不到 
            cout<<word<<endl;//輸出string到控制台 
        }
    }
    in.close();
    in.clear();
    
    return 0;
} 

ifstream &openfile(ifstream &in, string &filename){
    in.close();
    in.clear();
    
    in.open(filename.c_str());
    
    return in;
}
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

//字符串格式轉換 
int main(){
    
    int val1=100,val2=500;
    string line, word;
    ostringstream out;
    out<<"val1: "<<val1<<"\n"
        <<"val2: "<<val2<<"\n";
    
    cout<<out.str()<<endl;
    
    string dump;
    
    istringstream in(out.str());
    in>>dump>>val1>>dump
        >>dump>>val2>>dump;
    
    cout<<val1<<"--"<<val2<<endl;    
    
    return 0;
} 

 



 
 注意: i或o是相對內存來說的。將內容讀入內存,是in;將內存中的內容輸出,是out。
 
 
 
參考:
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM