C++<第三十七篇>:文件操作

文件操作是程序開(kāi)發(fā)中不可缺少的一部分遇西,任何需要數(shù)據(jù)存儲(chǔ)的軟件都需要進(jìn)行文件操作。文件操作包括打開(kāi)文件、讀文件和寫(xiě)文件风秤。

(1)C++ 中的流類庫(kù)

C++ 語(yǔ)言中為不同類型數(shù)據(jù)的標(biāo)準(zhǔn)輸入和輸出定義了專門(mén)的類庫(kù),類庫(kù)中主要有 ios扮叨、istream缤弦、ostream、ifstream彻磁、istrstream碍沐、iostream、ostrstream衷蜓、ofstream累提、fstream、strstream恍箭,它們之間的繼承關(guān)系如下:

image.png

這些流類的基本名稱如下:

ios:根基類
istream:輸入流類
ostream:輸出流類
ifstream:輸入文件流類
istrstream:輸入字符串流類
iostream:輸入輸出流類
ostrstream:輸出字符串流類
ofstream:輸出文件流
fstream:文件流
strstream:字符串流

這些流類都定義在 I/O 標(biāo)準(zhǔn)庫(kù) <iostream>刻恭、<fstream>、<strstream> 中。

(2)字符串流的使用
char buf[] = "12345678";
int a, b;
istrstream s1(buf);
s1 >> a;
istrstream s2(buf, 3);
s2 >> b;
cout << a + b << endl;

ostrstream   s3;
s3 << "123" << ends;
cout << s3.str() << endl;
delete s3.str();

以上代碼的運(yùn)行結(jié)果是:

12345801
123

使用 istrstream 將字符串轉(zhuǎn)成整型鳍贾,a = 12345678, b = 123鞍匾, a + b = 12345801。
使用 ostrstream 將123存在緩存骑科,最后輸出橡淑。

(3)打開(kāi)文件

只有利用文件流與磁盤(pán)上的文件相關(guān)聯(lián)之后才能對(duì)文件進(jìn)行操作,這個(gè)關(guān)聯(lián)的過(guò)程稱為打開(kāi)文件咆爽。

打開(kāi)文件的方式有兩種:

(1)在創(chuàng)建文件流時(shí)利用構(gòu)造函數(shù)打開(kāi)文件梁棠,舉例代碼如下:

     ofstream outfile("test.txt", ios::out);
     ifstream infile("test.txt", ios::in);
     fstream file("test.txt", ios::in|ios::out);

ofstream 是文件流類,它還可以是 ifstream 斗埂、fstream符糊;
outfile 是文件流對(duì)象名稱;
在構(gòu)造函數(shù)中有兩個(gè)參數(shù)呛凶,第一個(gè)參數(shù)是:文件名路徑(絕對(duì)路徑或者相對(duì)路徑)男娄;
構(gòu)造函數(shù)的第二個(gè)參數(shù)是:打開(kāi)方式,打開(kāi)放在是 ios 類中定義漾稀,有輸入方式模闲、輸出方式、追加方式等崭捍,如下:

ios::in:以輸入方式打開(kāi)文件尸折,文件只能讀取,不能改寫(xiě)殷蛇;
ios::out:以輸出方式打開(kāi)文件实夹,只能改寫(xiě),不能讀攘肋洹收擦;
ios::app:以追加方式打開(kāi)文件,打開(kāi)后文件指針在文件尾部谍倦,可改寫(xiě);
ios::ate:打開(kāi)已存在的文件泪勒,文件指針指向文件尾部昼蛀,可改寫(xiě);
ios::binary:以二進(jìn)制方式打開(kāi)文件圆存;
ios::trunc:打開(kāi)文件進(jìn)行寫(xiě)操作叼旋,如果文件已經(jīng)存在,清除文件中的數(shù)據(jù)沦辙;
ios::nocreate:打開(kāi)已存在的文件夫植,如果文件不存在,則打開(kāi)失敗,文件不會(huì)創(chuàng)建详民;
ios::noreplace:創(chuàng)建新文件延欠,如果文件已經(jīng)存在,打開(kāi)失敗沈跨,不覆蓋由捎;
ios::in|ios::out:以讀寫(xiě)方式打開(kāi)文件,對(duì)文件可讀可寫(xiě)饿凛;
ios::in|ios::binary:以二進(jìn)制方式打開(kāi)文件狞玛,進(jìn)行讀操作;

(2)利用 open 函數(shù)打開(kāi)磁盤(pán)文件涧窒,代碼舉例如下:

    ifstream infile;
    infile.open("text.txt", ios::in);
    ofstream outfile;
    outfile.open("text.txt", ios::out);
    fstream file;
    file.open("text.txt", ios::in|ios::in);

另外心肪,打開(kāi)文件還存在第三個(gè)參數(shù):

    ifstream infile("test.txt", ios::in, 0);

    ifstream infile;
    infile.open("text.txt", ios::in, 0);

第三個(gè)參數(shù)是:文件的訪問(wèn)方式,取值如下:

0:普通文件
1:只讀文件
2:隱含文件
3:系統(tǒng)文件
(4)文件的讀寫(xiě)

在對(duì)文件進(jìn)行操作時(shí)纠吴,必然離不開(kāi)讀寫(xiě)文件硬鞍。在使用程序查看文件內(nèi)容時(shí),首先要讀取文件呜象,而要修改文件內(nèi)容時(shí)膳凝,則需要向文件中寫(xiě)入數(shù)據(jù)。

文件輸入流是 ifstream恭陡,文件輸出流時(shí) ofstream蹬音,它們有一些成員函數(shù):

attach:在一個(gè)打開(kāi)的文件與流之間建立連接;
close:刷新未保存的數(shù)據(jù)后關(guān)閉文件休玩;
flush:刷新流著淆;
open:打開(kāi)一個(gè)文件并把它與流連接;
put:把一個(gè)字節(jié)寫(xiě)入流中拴疤;
rdbuf:返回與流連接的 filebuf 對(duì)象永部;
seekp:設(shè)置流文件指針位置;
setmode:設(shè)置流為二進(jìn)制或文本模式呐矾;
tellp:獲取流文件指針位置苔埋;
write:把一組字節(jié)寫(xiě)入流中;

文件流對(duì)象 ftream 是 ifstream 和 ofstream 的綜合體蜒犯,它的成員函數(shù)有:

get:從文件讀取一個(gè)字符组橄;
getline(str,n,'\n'):從文件讀取字符存入字符串中,直到讀取n-1個(gè)字符或遇到“\n”時(shí)結(jié)束罚随;
peek:查找下一個(gè)字符玉工,但不從文件中取出;
put:將一個(gè)字符寫(xiě)入文件淘菩;
putback:對(duì)輸入流放回一個(gè)字符遵班,但不保存;
eof:如果讀取超過(guò) eof,返回True狭郑;
ignore(n):跳過(guò) n 個(gè)字符腹暖,參數(shù)為空時(shí),表示跳過(guò)下一個(gè)字符愿阐;

文件讀寫(xiě)操作演示代碼如下:

char buf[128];
ofstream ofile("test.txt");
for (int i = 0; i < 5; i++)
{
    memset(buf, 0, 128); // 對(duì)數(shù)組進(jìn)行初始化
    cin >> buf;   // 在控制臺(tái)輸入數(shù)據(jù)
    ofile << buf; // 將輸入的數(shù)據(jù)保存到文件中
}
ofile.close(); // 關(guān)閉流

ifstream ifile("test.txt");
while (!ifile.eof())
{
    char ch;
    ifile.get(ch); // 讀取文件
    if (!ifile.eof()) // 判斷是否是結(jié)尾
    {
        cout << ch;
    }
}
cout << endl;
ifile.close(); // 關(guān)閉流

以上代碼的邏輯是:

(1)文件輸出流 ofile 與文件 test.txt 關(guān)聯(lián)微服;
(2)在控制臺(tái)輸出5個(gè)數(shù)據(jù);
(3)將數(shù)據(jù)存入文件缨历;
(4)文件輸入流 ifile 與文件 test.txt 關(guān)聯(lián)以蕴;
(5)讀取文件,并將數(shù)據(jù)打印到控制臺(tái)辛孵;

下面再舉一個(gè)文件復(fù)制的例子:

ifstream infile;
ofstream outfile;
char name[20];
char c;
infile.open("test.txt"); // 打開(kāi)文件
if (!infile) // 判斷文件是否存在
{
    cout << "原文件不存在丛肮!" << endl;
    exit(1);
}

outfile.open("test_copy.txt"); // 打開(kāi)文件,如果文件不存在魄缚,則創(chuàng)建

while (infile.get(c)) 
{
    outfile << c;
}
infile.close();
outfile.close();
(5)文件錯(cuò)誤與狀態(tài)

在 I/O 流的操作過(guò)程中可能出現(xiàn)各種錯(cuò)誤宝与,每一個(gè)流都有一個(gè)狀態(tài)標(biāo)志字,以指示是否發(fā)生了錯(cuò)誤及出現(xiàn)了哪種類型的錯(cuò)誤冶匹,這種處理技術(shù)與格式控制標(biāo)志字是相同的习劫。

static constexpr _Iostate goodbit = static_cast<_Iostate>(0x0);
static constexpr _Iostate eofbit  = static_cast<_Iostate>(0x1);
static constexpr _Iostate failbit = static_cast<_Iostate>(0x2);
static constexpr _Iostate badbit  = static_cast<_Iostate>(0x4);

源碼中,可以看出文件的四種狀態(tài):goodbit嚼隘、eofbit诽里、failbit、badbit飞蛹,它們的默認(rèn)值分別是 0谤狡、1、2卧檐、4墓懂。

ios 類提供了以下成員函數(shù)來(lái)檢測(cè)或設(shè)置流的狀態(tài):

file.good(); // 正常
file.eof(); // 輸入流以結(jié)束,無(wú)字符可讀入
file.fail(); // 上次讀/寫(xiě)操作失敗霉囚,但流仍可使用
file.bad(); // 無(wú)效的讀/寫(xiě)操作捕仔,流不再可用

ios 的 rdstate() 函數(shù)可以獲取文件的最終狀態(tài),文件的狀態(tài)可能只有一種盈罐,比如:

rdstate() = goodbit逻澳;

文件的狀態(tài)還可以存在多種,比如:

rdstate() = eofbit | failbit暖呕;

使用 | 運(yùn)算符計(jì)算出最終的文件狀態(tài)。那么苞氮,如何判斷當(dāng)前文件是什么狀態(tài)呢湾揽?

file.good() = rdstate() & goodbit;
file.eof() = rdstate() & eofbit;
file.fail() = rdstate() & failbit库物;
file.bad() = rdstate() & badbit霸旗;

使用 & 運(yùn)算符可以判斷文件是什么狀態(tài)。

去除狀態(tài)也很簡(jiǎn)單戚揭,直接調(diào)用

file.clear(ios_base::goodbit);
或
file.clear(ios_base::eofbit);
或
file.clear(ios_base::failbit);    
或
file.clear(ios_base::badbit);

即可诱告。

(6)文件的追加

在文件寫(xiě)操作中,除了將輸出文件的內(nèi)容完全覆蓋重寫(xiě)之外民晒,還可以直接在文件的末尾追加數(shù)據(jù)精居。

ofstream outfile("text.txt", ios::app);

以上代碼中,文件輸出流的第二個(gè) ios::app 表示以追加的方式寫(xiě)數(shù)據(jù)潜必。

追加的方式還可以用 seekp 來(lái)實(shí)現(xiàn)靴姿,代碼如下:

fstream iofile("test.txt",ios::in | ios::out);
if (iofile) // 如果文件存在
{
    iofile.seekp(0, ios::end); // 將文件指針移動(dòng)到末尾
    iofile << endl; // 寫(xiě)入換行符
    iofile << "zhangsan"; // 寫(xiě)入新的文本
}
(7)文件結(jié)尾的判斷

在操作文件時(shí),經(jīng)常需要判斷文件是否結(jié)束磁滚,使用過(guò)eof()可以實(shí)現(xiàn)佛吓。
另外,也可以通過(guò)其他方法來(lái)判斷垂攘,例如使用流的 get() 方法维雇,如果文件指針指向文件末尾,get() 方法獲取不到數(shù)據(jù)就返回 -1晒他,這樣也可以作為判斷結(jié)束的方法吱型。

(8)設(shè)置文件指針位置的函數(shù)

要實(shí)現(xiàn)在指定位置讀寫(xiě)文件的功能,首先要了解文件指針是如何移動(dòng)的仪芒,用于設(shè)置文件指針位置的函數(shù)如下:

seekg:位移字節(jié)數(shù)唁影,相對(duì)位置用于輸入文件中指針的移動(dòng);
seekp:位移字節(jié)數(shù)掂名,相對(duì)位置用于輸出文件中指針的移動(dòng)据沈;
tellg:用于查找輸入文件中的文件指針位置;
tellp:用于查找輸入文件中的文件指針位置饺蔑;

位移字節(jié)數(shù)是移動(dòng)指針的位移量锌介,相對(duì)位置是參照位置,取值如下:

ios::beg:文件頭部猾警;
ios::end:文件尾部孔祸;
ios::cur:文件指針的當(dāng)前位置;
(9)刪除文件

使用 remove(file) 可以實(shí)現(xiàn)刪除文件功能发皿,它的返回值類型是int崔慧,如果返回值是0,則刪除成功穴墅,如果是-1惶室,則刪除失敗温自。

演示代碼如下:

if (!remove("test.txt")) 
{
    cout << "文件已刪除" << endl;
}
else
{
    cout << "刪除失敗" << endl;
}

[本章完...]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市皇钞,隨后出現(xiàn)的幾起案子悼泌,更是在濱河造成了極大的恐慌,老刑警劉巖夹界,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馆里,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡可柿,警方通過(guò)查閱死者的電腦和手機(jī)鸠踪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趾痘,“玉大人慢哈,你說(shuō)我怎么就攤上這事∮榔保” “怎么了卵贱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)侣集。 經(jīng)常有香客問(wèn)我键俱,道長(zhǎng),這世上最難降的妖魔是什么世分? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任编振,我火速辦了婚禮,結(jié)果婚禮上臭埋,老公的妹妹穿的比我還像新娘踪央。我一直安慰自己,他們只是感情好瓢阴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布畅蹂。 她就那樣靜靜地躺著,像睡著了一般荣恐。 火紅的嫁衣襯著肌膚如雪液斜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天叠穆,我揣著相機(jī)與錄音少漆,去河邊找鬼。 笑死硼被,一個(gè)胖子當(dāng)著我的面吹牛示损,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嚷硫,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼屎媳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼夺溢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起烛谊,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘉汰,沒(méi)想到半個(gè)月后丹禀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞋怀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年双泪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片密似。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡焙矛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出残腌,到底是詐尸還是另有隱情村斟,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布抛猫,位于F島的核電站蟆盹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏闺金。R本人自食惡果不足惜逾滥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望败匹。 院中可真熱鬧寨昙,春花似錦、人聲如沸掀亩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)归榕。三九已至尸红,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刹泄,已是汗流浹背外里。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留特石,地道東北人盅蝗。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像姆蘸,于是被迫代替她去往敵國(guó)和親墩莫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芙委,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • [轉(zhuǎn)]C/C++ 文件讀寫(xiě)操作總結(jié) 在編程的過(guò)程中,文件的操作是一個(gè)經(jīng)常用到的問(wèn)題狂秦,在C++Builder中灌侣,可以...
    天之道天知道閱讀 5,199評(píng)論 0 7
  • 轉(zhuǎn)載(https://www.cnblogs.com/MrYuan/p/5383408.html) 基于C的文件操...
    送分童子笑嘻嘻閱讀 452評(píng)論 0 0
  • c++文件操作: 文件操作三大步(邏輯如下):1、打開(kāi)文件2裂问、讀寫(xiě)文件3侧啼、關(guān)閉文件 介紹下頭文件: #includ...
    北影拼搏閱讀 755評(píng)論 0 2
  • c++文件操作詳解 C++ 通過(guò)以下幾個(gè)類支持文件的輸入輸出: ofstream: 寫(xiě)操作(輸出)的文件類 (由o...
    鮑陳飛閱讀 1,778評(píng)論 0 2
  • 1. 流 流:數(shù)據(jù)從一個(gè)對(duì)象到另一個(gè)對(duì)象的傳輸。 功能:標(biāo)準(zhǔn)輸入輸出+文件處理 分類含義文本流一串ASCII字符二...
    jdzhangxin閱讀 1,383評(píng)論 0 4