ifstream默认不抛异常,需检查is_open()或failbit;写入中文乱码主因是locale与文件编码不匹配,推荐wofstream配codecvt_utf8;二进制读写应避免eof(),改用read()和gcount()。
failbit 和 is_open()
默认情况下,ifstream 构造或 open() 失败不会抛异常,对象进入失效状态但不崩溃。常见现象是后续 getline() 或 >> 读不出内容,变量值还是初始值。
if (!fin.is_open()) 或 if (fin.fail())
fin.exceptions(ifstream::failbit | ifstream::badbit);,这样失败会直接抛 std::ios_base::failure
std::locale::global(std::locale("")); (仅限本地环境),否则可能因编码不匹配打不开setf(ios::unitbuf)
乱码主因不是缓冲区,而是流的 locale 和文件实际编码不一致。VS 默认窄字符流用系统 ANSI(如 GBK),而源文件常为 UTF-8,写入字节流后用 UTF-8 编辑器打开就显示乱码。
ofstream 直接写 std::string 中文——它只是按字节转发,不转码std::wofstream + std::locale 绑定 UTF-8 facet(需 C++11 以上):std::wofstream wout("out.txt");
wout.imbue(std::locale(wout.
getloc(), new std::codecvt_utf8));
wout << L"你好"; std::string)以二进制方式写入,确保编辑器用 UTF-8 解码——此时不用改 locale,但必须用 ofstream("xxx", ios::binary)
fstream 时,seekg() 和 seekp() 要分开调fstream 同时维护输入位置(get pointer)和输出位置(put pointer),二者独立。混用 read() 和 write() 时,不显式重定位会导致读写错位。
seekg(0) 回开头;读完想追加写,得 seekp(0, ios::end)
ios::in | ios::out 模式打开时,文件必须已存在(ios::trunc 会清空,ios::app 会强制写末尾,不支持随机读写)ofstream 创建并写,再用 ifstream 读;或用 fstream 加 ios::in | ios::out | ios::ate,然后手动 seekg(0)
while (!fin.eof())
eof() 只在**尝试读取失败后**才返回 true,循环体末尾检测会导致多执行一次无效读取,甚至使 fin 进入 failbit 状态,后续操作全部失效。
while (getline(fin, line)) { ... } 或 while (fin >> value) { ... }
read() 配合 gcount() 判断实际读取字节数,避免依赖 eof()
fin.rdbuf()->pubsetbuf(buffer, bufsize);(注意:必须在 open 前调用)is_open() 返回 false 却不告诉你为什么,这时候看一眼 errno 或用 strerror(errno) 才能知道到底是 “No such file” 还是 “Permission denied”。