3 - 文件流fstream
在<fstream>
头文件中定义了输入和输出文件流:std::ifstream
提供了文件流的输入功能,因为是文件 -> 内存;std::ofstream
提供了文件流的输出功能,因为是内存 -> 文件;此外,还有综合两者的双向文件流std::fstream
。
文件流
构造
文件流的构造函数可以接收文件名以及打开文件的模式作为参数:
// 使用默认构造函数, 并打开文件
ifstream ifs;
ifs.open("test.txt");
// 构造对象时顺便打开文件
ifstream ifs("test.txt");
// 还能指定它打开文件的模式
ifsteam ifs("test.txt", ios_base::ate)
下表是可以指定给文件流的文件打开模式:
常量 | 说明 |
---|---|
ios_base::app | 以追加模式写文件,即每次写入前,将写入位置移到文件末尾 |
ios_base::ate | 打开文件后,马上将位置移到文件末尾(仅一次) |
ios_base::binary | 以二进制模式读写文件 |
ios_base::in | 打开文件,从开头开始读取。是ifstream 的默认模式。 |
ios_base::out | 打开文件,从开头开始写入,并覆盖已有数据。是ofstream 的默认模式。 |
ios_base::trunc | 打开文件,并删除已有数据。 |
二进制模式和文本模式的不同:二进制模式就是逐字节读写,读下啥就是啥;文本模式中,对行结束符会有一些转换操作,例如Windows的换行是
\r\n
,而Unix的换行是\n
,读/写文件前需要进行转换。
这些模式也能通过|
组合:
ios_base::out | ios_base::binary | ios_base::trunc
标准读写
和用户流的标准读写类似,文件流的标准读写模板如下,客户输入文件名,有这个文件就输出文件内容,没有就报错:
string fileName;
string fileContent;
while (cin >> fileName, !cin.eof())
{
if (cin.bad())
{
throw runtime_error("Cin is corrupted");
}
ifstream ifs(fileName);
if (ifs.is_open())
{
while (getline(ifs, fileContent))
{
cout << fileContent << endl;
}
if (ifs.bad())
{
throw runtime_error("Ifs is corrupted");
}
ifs.close();
}
else
{
ifs.clear();
ifs.ignore(numeric_limits<streamsize>::max(), '\n');
cerr << "File: " << fileName << " does not exist!" << endl;
}
}
位置操纵
就像C语言中可以通过fseek()
等函数操纵文件指针那样,所有的输入输出流都有seekx()
和tellx()
方法。
seekx()
对于输入流,这个方法实际上是seekg()
(g表示get);对于输出流,这个方法实际上是seekp()
(p表示put)。seekx()
有两个重载版本:
接收一个实参——绝对位置,并将流的读/写位置定位到这里。
接收一个偏移量和一个位置,将流的读/写位置定位到 该位置+偏移量 的地方。其中,位置的定义如下:
位置 说明 ios_base::beg
流的开头 ios_base::end
流的末尾 ios_base::cur
流的当前位置
使用例:
// 类型(std::streamoff, std::streampos)
outStream.seekp(2, ios_base::beg);
inStream.seekg(-3, ios_base::end);
tellx()
查询流当前的读/写位置.
流的链接
通过流的链接操作可以实现 访问即刷新(flush-on-access) 的效果,即当从输入流请求数据时,链接的输出流会自动刷新。例如cin
和cout
,每当从cin
输入数据时,cout
都会自动刷新。
可以通过tie()
方法完成流的链接:
ifstream inFile("a");
ofstream outFile("b");
// 将输入流链接到输出流
inFile.tie(&outFile);
// 输出流里输出点东西, 此时没有刷新
outFile << "123";
// 让输入流触发输出流刷新
inFile >> "456";
// 输出流刷新了
要想解除链接,可以绑定nullptr
。两个输出流也能绑定,这样可以维持两个文件的同步。
参考资料
- 飘零的落花 - 现代C++详解
- C++20高级编程