C++基礎5:文件

1. 流

  • 流:數據從一個對象到另一個對象的傳輸。
  • 功能:標準輸入輸出+文件處理
分類 含義
文本流 一串ASCII字符
二進制流 一串二進制

2. 流類型

標準庫定義了三大類流類型:標準I/O流、文件流、字符串流

  • 標準I/O流
    • ios是抽象類
    • ostreamcoutclogcerr的類
    • istreamcin的類
  • 文件流類型
    • ifstream從文件讀取數據
    • ofstream向文件寫入數據
    • iofstream文件讀寫數據
  • 字符串流類型
    • istringstreamstring讀取數據
    • ostringstreamstring寫入數據
    • iostringstream讀寫string數據

3. 流對象

通常標準I/O流對象是全局對象不需要定義,而文件流對象和字符串流對象需要用戶定義。

標準I/O流對象有以下四個:

No. 全局流對象 名稱 緩存
1 cout 標準輸出流 帶緩存
2 cin 標準輸入流 帶緩存
3 clog 標準日志流 帶緩存
4 cerr 標準錯誤流 無緩存

注意:流對象通常都不能復制。

4. 流對象狀態

流對象狀態在某一個時刻必定處于以下四個狀態之一。

No. 狀態 含義
1 good() 前一個流操作成功
2 eof() 到輸入尾/文件尾
3 fail() 發生意外事情(讀取失敗)
4 bad() 發生意外嚴重事情(磁盤讀取失敗)

5. I/O操作

I/O操作主要有如下五種:

  • 輸入操作:in >> x或者getline(in,s)
  • 輸出操作:out << x
  • 操作符
  • 流狀態
  • 格式化

  • 輸出流默認設置
類型 進制 寬度 對齊 填充 精度
整數 十進制 0 右對齊 空格 1
實數 十進制 0 右對齊 空格 6位數
字符串 - 0 右對齊 空格 字符串實際長度
  • 格式控制
  • 格式控制成員函數
流對象.格式控制函數(實參)
  • 預定義格式控制函數
預定義格式控制函數(實參)
  • 流的輸出控制格式
作用 格式控制成員函數 預定義格式控制函數 預定義格式控制符/操作子 效果持續
進制 flags() setf() unsetf() setiosflags() dec oct hex showbase 能持續
寬度 width(n) setw(n) - 不能持續
對齊 flags() setf() unsetf() setiosflags() right left internal 能持續
填充 fill(c) setfill(c) - 能持續
精度 precision(n) setprecision(n) - 能持續
  • 流的輸出控制格式:dec oct hex
  • 數據輸入成員函數
    字符輸入成員函數:get()
    字符串輸入成員函數:getline()
  • 數據輸出成員函數:put()

1. 對齊方式

flag manipulator 作用
ios::left left 居左
ios::right right 居右
ios::internal internal 輸出符號或進制后填充
  • 成員函數方式
#include <iostream>
using namespace std;
int main(){
    int n = -11;
    cout.width(6);
    cout.flags(ios::right);
    cout << n << endl;

    cout.width(6);
    cout.flags(ios::left);
    cout << n << endl;

    cout.width(6);
    cout.flags(ios::internal);
    cout << n << endl;
}
  • 操作子方式
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
    int n = -11;
    cout << setw(6) << right << n << endl;
    cout << setw(6) << left << n << endl;
    cout << setw(6) << internal << n << endl;
}
  • 混合方式
#include <iostream>
using namespace std;
int main(){
int n = -11;
    cout.width(6); cout << left << n << endl;
    cout.width(6); cout << right << n << endl;
    cout.width(6); cout << internal << n << endl;
}

2. 整數輸出格式

flag manipulator 作用 是否默認
ios::dec dec 十進制
ios::oct oct 八進制
ios::hex hex 十六進制
ios::uppercase uppercase 使用大寫輸出十六進制
ios::showbase showbase 輸出帶有進制的字符
  • 成員函數方式
#include <iostream>
using namespace std;
int main(){
    int n = 11;
    cout.flags(ios::dec);
    cout << n << endl;
    cout.flags(ios::hex);
    cout << n << endl;
    cout.flags(ios::oct);
    cout << n << endl;

    cout.flags(ios::showbase|ios::dec);
    cout << n << endl;
    cout.flags(ios::showbase|ios::oct);
    cout << n << endl;
    cout.flags(ios::showbase|ios::hex);
    cout << n << endl;

    cout.flags(ios::showbase|ios::uppercase|ios::dec);
    cout << n << endl;
    cout.flags(ios::showbase|ios::uppercase|ios::oct);
    cout << n << endl;
    cout.flags(ios::showbase|ios::uppercase|ios::hex);
    cout << n << endl;
}
  • 操作子方式
#include <iostream>
using namespace std;
int main(){
    int n = 11;
    cout << dec << n << endl;
    cout << hex << n << endl;
    cout << oct << n << endl;

    cout << showbase << dec << n << endl;
    cout << oct << n << endl;
    cout << hex << n << endl;

    cout << uppercase << dec << n << endl;
    cout << oct << n << endl;
    cout << hex << n << endl;
}

3. 浮點數輸出格式

flag 作用 是否默認 精度
ios::defaultfloat 默認浮點數格式 最多保留多少位數字
ios::scientific 科學計數法輸出浮點數 小數點后最多保留多少位數字
ios::fixed 定點數方式輸出實數 小數點后最多保留多少位數字

如果浮點數沒有小數時默認不顯示小時點,使用ios::showpoint可以強制輸出浮點數時,必須帶小數點。

定點數方式比浮點數方式更精確
取浮點數精確度時,設置ios::fixed

  • 成員函數方式
#include <iostream>     // cout, std::fixed, std::scientific
using namespace std;
int main () {
  double a = 3.1415926534;
  double b = 2006.0;
  double c = 1.0e-10;

  cout.precision(5);
  cout << "default:\n";
  cout << a << endl << b << endl << c << endl;
  
  cout << "fixed:\n";
  cout.flags(ios::fixed);
  cout << a << endl << b << endl << c << endl;

  cout << "scientific:\n";
  cout.flags(ios::scientific);
  cout << a << endl << b << endl << c << endl;

  return 0;
}
  • 操作子方式
#include <iostream>     // std::cout, std::fixed, std::scientific
#include <iomanip>
using namespace std;
int main () {
  double a = 3.1415926534;
  double b = 2006.0;
  double c = 1.0e-10;

  cout << setprecision(5)
       << "default:\n"
       << a << endl << b << endl << c << endl;
  
  cout << "fixed:\n" << fixed
       << a << endl << b << endl << c << endl;

  cout << "scientific:\n" << scientific
       << a << endl << b << endl << c << endl;

  return 0;
}
  • 混合方式
#include <iostream>     // std::cout, std::fixed, std::scientific
int main () {
  double a = 3.1415926534;
  double b = 2006.0;
  double c = 1.0e-10;

  std::cout.precision(5);
  std::cout << "default:\n";
  std::cout << a << '\n' << b << '\n' << c << '\n\n'
  
  std::cout << "fixed:\n" << std::fixed;
  std::cout << a << '\n' << b << '\n' << c << '\n\n'

  std::cout << "scientific:\n" << std::scientific;
  std::cout << a << '\n' << b << '\n' << c << '\n\n';

  return 0;
}

4.布爾類型輸出格式

flag manipulator 作用
ios::boolalpha boolalpha bool值以字符串true/false輸出

5. 其它

flag manipulator 作用 默認
ios::showpos showpos 輸出十進制0或者正數時,帶+號
  • 成員函數方式
#include <iostream>     // std::cout, std::showpos, std::noshowpos
using namespace std;
int main () {
  int p = 1;
  int z = 0;
  int n = -1;
  cout.setf(ios::showpos); cout << p << '\t' << z << '\t' << n << endl;
  cout.unsetf(ios::showpos); cout << p << '\t' << z << '\t' << n << endl;
  return 0;
}
  • 操作子方式
#include <iostream>     // std::cout, std::showpos, std::noshowpos
using namespace std;
int main () {
  int p = 1;
  int z = 0;
  int n = -1;
  cout << showpos   << p << '\t' << z << '\t' << n << endl;
  cout << noshowpos << p << '\t' << z << '\t' << n << endl;
  return 0;
}

復數虛部a+bi使用showpos非常合適。

問題

  1. 浮點數八進制/十六進制輸出結果?
  2. 下列代碼為什么能轉化成十六進制?
#include <iostream>
#include <iomanip> // setiosflags() , ios::hex
using namespace std;
int main(){
        cout << setiosflags(ios::hex) << 10 << endl;
}

最新版C++的iostream庫中,在使用setiosflags()前要先使用resetiosflags()清除舊有相應信息。

cout << resetiosflags(ios::basefield)<< setiosflags(ios::hex) << 10 << endl;

以下三類格式化在使用setiosflags(),要先使用resetiosflags()清除舊有相應信息。

stringstream

  • 字符串轉化數字
istringstream iss(str);
int n;
iss >> n;

C++11提供如下函數簡化字符串轉數字

  • stoi() stol() stoul() stoll() stoull()

  • stof() stod() stold()

  • 數字轉化字符串

int n;
ostringstream oss;
oss << n;
oss.str();

練習

    vector<string> split(const string& str){
        vector<string> res;
        istringstream iss(str);
        string s;
        while(iss >> s){
            res.push_back(s);
        }
        return res;
    }

  • C++文件讀寫
    文件:文件名+文件內容(有序數據集合)
    文件名:字符序列
    文件數據格式:二進制文件/文本文件

  • C++文件操作流程

  1. 打開文件
  2. 讀寫文件
  3. 關閉文件
  • 打開/關閉文件
操作 代碼
定義讀文件流對象 ifstream 讀文件流對象
定義寫文件流對象 ofstream 寫讀文件流對象
定義讀寫文件流對象 fstream 讀寫讀文件流對象
成員函數打開文件 文件流對象.open(文件名,文件打開方式)
構造函數打開文件 文件流類 對象(文件名,文件打開方式)
判斷文件是否打開 !文件流對象
關閉文件 文件流對象.close(變量)
  • 文本文件讀寫
操作 代碼
提取運算符讀文件 文件流對象 >> 變量
插入運算符寫文件 文件流對象 << 變量
成員函數讀文件 文件流對象.get(變量)
成員函數寫文件 文件流對象.put(變量)
  • 二進制文件讀寫
操作 代碼
讀函數 read()
寫函數 write()
測試文件結束 eof()
  • 文件打開方式
類型 代碼
ios::in
ios::out
添加末尾 ios::app
已存在文件 ios::nocreate
未打開文件 ios::noreplace
二進制 ios::binary
  • 文件對象指針位置函數
操作 代碼
獲取讀位置 對象.tellg()
獲取寫位置 對象.tellp()
設置讀位置 對象.seekg()
設置寫位置 對象.seekp()
  • 函數后綴p表示put(輸出),后綴g表示get(輸入)。
  • 如果文件是以ios::app文本追加方式打開,指針位置默認在文件結束,其他情況默認在文件開頭。
  • 文件對象狀態函數
操作 代碼
判斷文件對象狀態是否正常 對象.good()
重置文件對象狀態 對象.clear()

流式文件類型

  1. stream流文件
  2. 文件指針FILE*

stream流文件讀寫

  • ifstream文件讀
ifstream fin(文件路徑);
fin >> 變量
fin.close();
  • ofstream文件寫
ofstream fout(文件路徑);
fout << 變量
fout.close();
  • fstream文件寫
fstream fs(文件路徑,ios::in|ios::out|ios::app);
if(fs){
  fs << 變量;
  fs.seekg(ios::beg);
  fs >> 變量;
  fs.close();
}

fstream的打開模式是否創建不存在的文件

No. 打開模式 是否創建不存在的文件
1 ios::in
2 ios::out
3 ios::in|ios::out
4 ios::in|ios::out|ios::app

先讀后寫

    fstream fs("test.txt",ios::in|ios::out|ios::app);
    if(fs){
        // 讀文件
        string str;
        while(fs >> str){
            cout << str << endl;
        }
        fs.clear();// 清除錯誤
        // 寫文件
        while(cin >> str){
            fs << str << endl;
        }
    }

先寫后讀

    fstream fs("test.txt",ios::in|ios::out|ios::app);
    if(fs){
        // 寫文件
        string str;
        while(cin >> str)
            fs << str << endl;
        
        // 讀文件  
        fs.seekg(ios::beg);
        while(fs >> str)
            cout << str << endl;
        // 后續如果對fs操作,需要清空fs狀態
    }else{
        cerr << "file not exist " << endl;
    }

文件指針FILE讀寫

  • FILE文件指針讀
FILE* fp = fopen(文件路徑,"r");
fscanf(,fp);
fclose(fp);
  • FILE文件指針寫
FILE* fp = fopen(文件路徑,"w");
fprintf(,fp);
fclose(fp); 

對象的序列化與反序列化
序列化:把對象轉化成文本/二進制
反序列化:把文本/二進制轉化成對象

文件重定向

freopen(文件路徑,操作,標準IO)

操作:讀(r) 寫(w)

  • 重定向寫
freopen("out.txt","w",stdout);
cout << "out data" <<endl;
  • 重定向讀
freopen("in.txt","r",stdin);
string str;
cin >> str;

幾種常見的文件讀取方式對比

  • ifstream + fin
  • freopen+cin+sync_with_stdio(false)
  • FILE* + fscanf
  • freopen+scanf
  • freopen+cin

實現日志模塊

freopen("test.log","w",stderr);
cerr << "FATAL";
cerr << "ERROR";
clog << "WARNING";
clog << "INFO";
clog << "DEBUG";

擴展閱讀

  • <<C++程序設計語言(第4部分:標準庫) 中文第四版>>:第38章 I/O流
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容