C++ 的文件 I/O 与普通 I/O 工作原理非常相似,只是增加了少量细节。标准库提供了 3 个基本的文件 I/O 类:
- ifstream(派生自- istream)——用于文件输入;
- ofstream(派生自- ostream)——用于## 文件输出;
- fstream(派生自- iostream)——用于文件输入/输出。
使用这些类前需包含头文件 <fstream>。
与 cout、cin、cerr、clog 等已自动就绪的流不同,文件流必须由程序员显式建立。但过程极其简单:只需用文件名作为参数构造相应文件流对象,随后便可使用 << 或 >> 进行读写。使用完毕后,可显式调用 close() 关闭文件;若忽略此步骤,当文件流对象离开作用域时,其析构函数会自动关闭文件。
文件输出
下面示例使用 ofstream 向文件写入数据:
#include <fstream>
#include <iostream>
int main()
{
    // 使用 ofstream 写文件,文件名为 Sample.txt
    std::ofstream outf{ "Sample.txt" };
    // 若无法打开文件
    if (!outf)
    {
        std::cerr << "Uh oh, Sample.txt could not be opened for writing!\n";
        return 1;
    }
    // 写入两行
    outf << "This is line 1\n";
    outf << "This is line 2\n";
    return 0;
    // outf 离开作用域后,析构函数自动关闭文件
}
在项目目录下将生成 Sample.txt,用文本编辑器打开即可看到两行内容。
也可使用 put() 一次写入单个字符。
文件输入
下面读取刚才创建的文件:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
    // 使用 ifstream 读文件
    std::ifstream inf{ "Sample.txt" };
    if (!inf)
    {
        std::cerr << "Uh oh, Sample.txt could not be opened for reading!\n";
        return 1;
    }
    std::string strInput{};
    while (inf >> strInput)           // 提取运算符以空白为分隔
        std::cout << strInput << '\n';
    return 0;
    // inf 离开作用域后析构,自动关闭文件
}
输出结果为:
This
is
line
1
This
is
line
2
显然,提取运算符遇到空白即分割。若想整行读取,应使用 getline():
std::string strInput{};
while (std::getline(inf, strInput))
    std::cout << strInput << '\n';
输出:
This is line 1
This is line 2
缓冲输出
C++ 的输出可能是缓冲的。数据先写入缓冲区,而非立即落盘。当缓冲区被“刷新”(flush)时,才会真正写入磁盘。关闭文件会强制刷新缓冲区并关闭文件。
若程序异常终止或显式调用 exit() 而未关闭文件,缓冲区可能未刷新,导致数据丢失。因此,在调用 exit() 前应显式关闭文件。
可手动刷新:
- 调用 ostream::flush()
- 向流插入 std::flush
- 使用 std::endl(会插入换行并刷新,但频繁使用可能影响性能;性能敏感场景可用'\n'代替)
文件打开模式
默认情况下,若文件已存在,写操作会覆盖原有内容。如需追加,可在构造 ofstream 时指定模式:
| 模式标志 | 含义 | 
|---|---|
| app | 追加模式:写入始终在文件末尾 | 
| ate | 打开后立即定位到文件尾 | 
| binary | 以二进制方式打开 | 
| in | 读模式( ifstream默认) | 
| out | 写模式( ofstream默认) | 
| trunc | 若文件已存在,先清空 | 
可用按位或 | 组合多个标志。fstream 默认使用 std::ios::in | std::ios::out;若文件不存在且仅用 in 模式,打开会失败。若需创建新文件,可仅用 out 模式。
示例:向已有文件追加两行:
#include <iostream>
#include <fstream>
int main()
{
    std::ofstream outf{ "Sample.txt", std::ios::app };
    if (!outf)
    {
        std::cerr << "Uh oh, Sample.txt could not be opened for writing!\n";
        return 1;
    }
    outf << "This is line 3\n";
    outf << "This is line 4\n";
    return 0;
}
文件内容变为:
This is line 1
This is line 2
This is line 3
This is line 4
显式打开文件(open())
同显式关闭文件一样,也可使用 open() 成员函数:
std::ofstream outf{ "Sample.txt" };
outf << "This is line 1\n";
outf << "This is line 2\n";
outf.close(); // 显式关闭
// 追加
outf.open("Sample.txt", std::ios::app);
outf << "This is line 3\n";
outf.close();
更多 open() 细节可查阅官方文档。
