10.1 文本文件 I/O 与路径
文件可以持久保存数据。内存中的变量会在程序结束后消失,但写入文件的数据可以保留下来。文件 I/O 指的是从文件输入,以及向文件输出。
C++ 也能使用 FILE* 这样的 C 风格文件 API,但本章只使用 C++ 风格文件 I/O:std::ifstream、std::ofstream、std::fstream 和 std::filesystem::path。
filesystem::path 与 stream
std::filesystem::path 表示文件或目录的位置。文件 stream 才真正执行读取和写入。
cpp
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
int main() {
std::filesystem::path path = "notes.txt";
std::ifstream input(path);
if (!input) {
std::cout << "无法打开 notes.txt" << std::endl;
return 1;
}
std::ostringstream buffer;
buffer << input.rdbuf();
std::string content = buffer.str();
std::cout << content;
return 0;
}创建 std::filesystem::path path = "notes.txt"; 不会读取文件。std::ifstream input(path); 才是向操作系统请求打开文件的动作。stream 离开作用域时会自动关闭。
注意
你可能会在 C 代码中看到
fopen、fprintf、fscanf 和 fclose。那些是 C 风格 API。在 C++ 入门代码中,优先使用文件 stream,因为它们更符合 C++ 对象、RAII 和 std::string 的风格。正在加载概念检查...
读取小型文本文件
对于小文件,一次性读成 std::string 很方便。
cpp
std::ifstream input("quote.txt");
std::ostringstream buffer;
buffer << input.rdbuf();
std::string text = buffer.str();
std::cout << text;如果想把所有行读成列表,可以用 std::getline,把每一行放进 std::vector<std::string>。
cpp
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
std::ifstream input("quote.txt");
std::vector<std::string> lines;
std::string line;
while (std::getline(input, line)) {
lines.push_back(line);
}
for (std::size_t i = 0; i < lines.size(); i++) {
std::cout << (i + 1) << ": " << lines[i] << std::endl;
}当文件很小时,可以这样整体读取。如果文件可能很大,应该优先逐行读取,第 10.2 节会继续讲。
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
I/O 失败
文件操作可能因为程序外部原因失败:文件不存在、路径指向目录、权限不足、磁盘不可用等。C++ stream 会通过 stream 状态表达失败。
cpp
std::ifstream input("notes.txt");
if (!input) {
std::cout << "无法读取 notes.txt" << std::endl;
}某些 std::filesystem 操作会抛出 std::filesystem::filesystem_error。
cpp
try {
auto size = std::filesystem::file_size("notes.txt");
std::cout << size << " bytes" << std::endl;
} catch (const std::filesystem::filesystem_error& error) {
std::cout << "文件操作失败:" << error.what() << std::endl;
}重点不是“永远 catch”或“永远 return”,而是决定程序在哪里能做出有用回应。
正在加载概念检查...