文件讀寫(xiě)是幾乎所有開(kāi)發(fā)語(yǔ)言中比較基礎(chǔ)和重要的應(yīng)用铸题,C++作為跨平臺(tái)語(yǔ)言,提供了以流為媒介的操作接口同仆,可以非常方便地實(shí)現(xiàn)各類文件的讀寫(xiě)倚舀。
fstream類
C++中文件讀寫(xiě)的主要接口類是fsteam
類细睡,fstream
類包含在頭文件<fstream>中谷羞,繼承自iostream
。
類似于iostream
與ostream
溜徙、istream
的關(guān)系湃缎,C++中還有ifstream
和ofstream
類,分別實(shí)現(xiàn)文件的讀和寫(xiě)萌京,注意ifstream
繼承自istream
雁歌,ofstream
繼承自ostream
;使用方式和fstream
基本一致知残,因此本文重點(diǎn)討論fstream
靠瞎。
fstream
對(duì)象內(nèi)部維護(hù)了一個(gè)filebuf
對(duì)象,作為流緩沖區(qū)求妹,用來(lái)暫存文件從物理存儲(chǔ)設(shè)備讀取之后或?qū)懭胫暗膬?nèi)容乏盐;filebuf
與物理存儲(chǔ)上的文件關(guān)聯(lián)的方式是調(diào)用fstream
的open
操作;一旦filebuf
與物理文件關(guān)聯(lián)之后制恍,對(duì)filebuf
的任何操作等同于對(duì)物理文件的操作父能。
fstream
的構(gòu)造函數(shù)有兩種形式,分別為默認(rèn)的不帶參的構(gòu)造函數(shù)净神,以及帶參數(shù)(filename何吝,openmode)的構(gòu)造函數(shù);調(diào)用帶參數(shù)的構(gòu)造函數(shù)時(shí)鹃唯,構(gòu)造的同時(shí)會(huì)關(guān)聯(lián)文件爱榕,從而不用調(diào)用open
操作。
fstream();
explicit fstream (const char* filename,
ios_base::openmode mode = ios_base::in | ios_base::out);
打開(kāi)/關(guān)閉文件
-
關(guān)聯(lián)(打開(kāi))文件 --
open
坡慌,open操作帶兩個(gè)輸入?yún)?shù)-
const char* filename
-- 文件名 -
ios_base::openmode mode
-- 關(guān)聯(lián)模式
-
open
操作內(nèi)部實(shí)際是調(diào)用rdbuf
(一個(gè)指向內(nèi)部filebuf
對(duì)象的指針)黔酥;如果fstream
已經(jīng)關(guān)聯(lián)到某個(gè)文件,再次調(diào)用open
將會(huì)失敽殚佟跪者;
簡(jiǎn)單說(shuō)一下openmode
,6種模式熄求,可以組合使用:
模式 | 解釋 | 說(shuō)明 |
---|---|---|
in | input | 只讀 |
out | output | 只寫(xiě) |
binary | binary | 文件以二進(jìn)制方式操作渣玲,而非文本方式 |
ate | at end | 定位到文件結(jié)尾,寫(xiě)操作將會(huì)清空原文件 |
app | append | 寫(xiě)文件操作從文件結(jié)尾開(kāi)始抡四,追加內(nèi)容 |
trunc | truncate | 文件原有內(nèi)容將會(huì)被忽略柜蜈,即覆蓋原文件 |
其中仗谆,容易誤解的是ate和app指巡,它們的區(qū)別可以參考ios::app與ios::ate的區(qū)別
文件是否關(guān)聯(lián)(打開(kāi))成功淑履,可以通過(guò)is_open
來(lái)判斷;
-
關(guān)閉文件 --
close
藻雪,讀寫(xiě)操作完成后秘噪,需要取消文件關(guān)聯(lián);
寫(xiě)文件
與寫(xiě)操作相關(guān)的函數(shù):
-
put
put
是向文件中寫(xiě)入字符勉耀,函數(shù)原型:ostream& put (char c)
; -
write
write
是向文件中寫(xiě)入字符串指煎,函數(shù)原型:ostream& write (const char* s, streamsize n)
; -
<<
操作符
<<
向文件寫(xiě)內(nèi)容和像cout
寫(xiě)操作相同,非常簡(jiǎn)單易用便斥;
寫(xiě)文件示例:
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ofstream ofs("test.txt");
std::string new_content = "pine_apple water_melon ";
ofs.write(new_content.c_str(), new_content.size());
ofs << "blue_berry" << std::endl;
ofs.put('l');
ofs.put('e');
ofs.put('m');
ofs.put('o');
ofs.put('n');
ofs.close();
}
寫(xiě)入后的文件內(nèi)容:
pine_apple water_melon blue_berry
lemon
讀文件
- 讀文件(針對(duì)文本文件)的一種方式是:
- 先獲取文件長(zhǎng)度至壤,可以配合使用
seekg
和tellg
函數(shù),seekg(streamoff off, ios_base::seekdir way)
可實(shí)現(xiàn)相對(duì)于某位置枢纠,去移動(dòng)下一個(gè)字符指針的偏移位置像街,最常用的是seekg(0, ios_base::end)
和seekg(0, ios_base::beg)
,從而將指針位置移動(dòng)到文件結(jié)尾或開(kāi)始晋渺;tellg()
返回當(dāng)前字符在文件流中的位置镰绎;可以先將指針移動(dòng)到結(jié)尾,然后獲取結(jié)尾字符的位置作為文件長(zhǎng)度木西,最后再將指針移動(dòng)回開(kāi)始的位置畴栖; - 將文件內(nèi)容全部或部分讀取,或者循環(huán)遍歷讀取字符或字符串八千;讀文件可調(diào)用
read
操作吗讶,read
可返回任意個(gè)數(shù)的字符到字符數(shù)組中,所以需要輸入2個(gè)參數(shù)恋捆,char* s
和streamsize n
;
- 先獲取文件長(zhǎng)度至壤,可以配合使用
附帶一個(gè)讀文件的demo實(shí)例(來(lái)自http://www.cplusplus.com/reference/istream/istream/read/)
// read a file into memory
#include <iostream> // std::cout
#include <fstream> // std::ifstream
int main () {
std::ifstream is ("test.txt", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
if (is)
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << is.gcount() << " could be read";
is.close();
// ...buffer contains the entire file...
delete[] buffer;
}
return 0;
}
讀文件除了采用read
函數(shù)以外照皆,還有多種方式,比如getline
函數(shù)鸠信,可以獲取每一行的內(nèi)容纵寝,默認(rèn)的分隔符是'\n',也可以通過(guò)參數(shù)設(shè)置分隔符星立;
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
- 另一種讀文件方式 -- 迭代器來(lái)讀取文件:
istream_iterator
可以從輸入流中連續(xù)讀取元素爽茴,一般以空格作為分割,可以像普通迭代器一樣遍歷文本文件绰垂,也可以直接將字符串讀入vector
容器中室奏。
代碼示例:
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
int main()
{
std::ifstream ifs("test.txt");
std::istream_iterator<std::string> iit(ifs);
std::istream_iterator<std::string> eos;
std::vector<std::string> vec(iit, eos);
std::cout << "vec size: " << vec.size() << std::endl;
for(size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
ifs.close();
return 0;
}
二進(jìn)制文件讀寫(xiě)
二進(jìn)制文件的讀寫(xiě)與文本文件讀寫(xiě)本質(zhì)上是一致的,只不過(guò)在關(guān)聯(lián)文件的時(shí)候劲装,應(yīng)當(dāng)組合std::ios::binary模式胧沫;以下給出一個(gè)簡(jiǎn)單的示例:
- 向一個(gè)二進(jìn)制文件寫(xiě)入0~9共9個(gè)數(shù)字:
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ofstream ofs("bin_test", std::ios::out | std::ios::binary);
for(size_t i = 0; i < 10; ++i) {
ofs.put(char(i));
}
ofs.close();
}
- 讀入剛才寫(xiě)的二進(jìn)制文件
#include <fstream>
#include <string>
#include <iostream>
int main(int argc, char** argv) {
std::ifstream ifs("bin_test", std::ios::in | std::ios::binary);
// get file content lenth
ifs.seekg(0, ifs.end);
int len = ifs.tellg();
ifs.seekg(0, ifs.beg);
// read data
char* data = new char[len];
ifs.read(data, 10);
for(size_t i = 0; i < len; ++i) {
std::cout << (int)(data[i]) << std::endl;
}
ifs.close();
delete[] data;
}