最稳妥的文本文件读写方式是分开使用 std::ifstream 和 std::ofstream;std::fstream 易因未正确指定模式导致覆盖或读失败,且需手动 open()。

用 std::ifstream 和 std::ofstream 读写文本文件最稳
绝大多数情况,别碰 std::fstream 单独用——它得手动 open() 并指定 ios::in | ios::out,稍不注意就覆盖原文件或读失败。直接拆开用更安全:std::ifstream 只读,std::ofstream 只写。
常见错误现象:std::ofstream 默认以 ios::out 打开,若文件存在会清空内容;没检查 .is_open() 就往里写,结果静默失败。
- 打开前务必检查:
if (!file.is_open()) { /* 处理错误 */ } - 写入后记得
file.flush()或让对象析构(自动 flush),否则缓冲区内容可能没落盘 - 路径含中文或空格时,Windows 下用
std::filesystem::u8path转 UTF-8 字符串再传给流(C++17+),否则大概率打不开 - Linux/macOS 对路径敏感,
"data.txt"和"./data.txt"可能指向不同位置,建议统一用绝对路径或确认当前工作目录
std::getline() 读行比 operator>> 更可靠
operator>> 遇空格/制表符/换行就停,根本读不全带空格的字段;std::getline() 按换行切,才是真“读一行”。
使用场景:配置文件、日志行、CSV(单行内无换行时)。
立即学习“C++免费学习笔记(深入)”;
-
std::getline(in, line)第二个参数是std::string&,不是char[],别传数组进去 - 如果文件最后一行没换行符,
std::getline()仍能读到该行,但循环条件别写while (in)——应该用while (std::getline(in, line)) - 想按其他字符分割(比如 CSV 的逗号),得自己用
line.find()+line.substr()切,std::getline()不支持自定义分隔符(除非重载)
二进制文件必须用 ios::binary 标志
不加这个标志,在 Windows 上读写 .png、.zip 这类文件会出问题:换行符 \r\n 被自动转成 \n,导致数据损坏。
性能影响:二进制模式跳过所有文本转换,I/O 略快;兼容性上,Linux/macOS 对文本/二进制模式区别小,但跨平台代码必须显式声明。
- 打开二进制文件:
std::ifstream bin_in("data.bin", std::ios::binary);std::ofstream bin_out("out.bin", std::ios::binary); - 读写原始字节用
.read()/.write(),参数是char*和字节数,不是字符串:bin_in.read(buffer, sizeof(buffer)); - 别用
std::string存二进制数据——它的.c_str()遇\0就截断;改用std::vector<char></char>或std::string_view(C++17+)
文件路径和异常处理容易被忽略的点
C++ 文件流默认不抛异常,.fail()、.bad()、.eof() 得手动查;很多人只查 is_open(),漏掉写一半磁盘满、权限不足等运行时错误。
真实场景中,相对路径行为依赖当前工作目录(不是可执行文件所在目录),调试时和双击运行时很可能不一样。
- 启用异常:
file.exceptions(std::ios::failbit | std::ios::badbit);之后open()、read()失败直接 throwstd::ios_base::failure - 获取当前可执行文件路径需系统 API(如 Windows 的
GetModuleFileName,Linux 的/proc/self/exe),标准库不提供 - 临时文件建议用
std::tmpnam()(注意线程不安全)或 C++17std::filesystem::temp_directory_path()
最麻烦的其实是路径拼接和编码——尤其在 Qt 或跨平台 GUI 程序里,std::fstream 接收的是窄字符串,而用户选的路径可能是 UTF-16(Windows)或 UTF-8(Linux),这里一错,文件就打不开,还没提示。










