文件操作是程序開(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)系如下:
這些流類的基本名稱如下:
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;
}
[本章完...]