最稳妥的二进制拷贝需显式指定二进制模式:std::ifstream 和 std::ofstream 构造时均须添加 std::ios::binary 标志,避免文本模式下换行符转换或 0x1A 截断问题。

用 std::ifstream 和 std::ofstream 做二进制拷贝最稳妥
直接用文本模式读写会导致换行符被悄悄转换(比如 Windows 的 \r\n 变成 \n),文件校验失败。必须显式指定二进制模式。
-
std::ifstream构造时加std::ios::binary标志 -
std::ofstream同样要加std::ios::binary,否则在 Windows 下可能截断0x1A字节(EOF 标记) - 别用
operator 或 <code>getline()——它们是为文本设计的,会停在\0或换行符上 - 推荐用
read()+write()配合缓冲区,比逐字节get()/put()快一个数量级
std::ifstream src("a.bin", std::ios::binary);
std::ofstream dst("b.bin", std::ios::binary);
char buf[8192];
while (src.read(buf, sizeof(buf))) {
dst.write(buf, src.gcount());
}
dst.write(buf, src.gcount()); // 处理末尾不足 8192 字节的部分
遇到 std::ios_base::failure 错误先查打开状态
这个异常常被误以为是读写失败,其实八成是文件根本没打开成功——比如路径错、权限不够、目标目录不存在。
- 构造
std::ifstream或std::ofstream后立刻检查.is_open(),别等读到一半才崩 - Windows 下路径含中文或空格时,确保传入的是 UTF-8 编码字符串(C++11 起支持
u8"路径")或使用std::filesystem::path转义 -
std::ofstream默认不创建父目录,"dir/sub/a.txt"会失败,除非dir/sub已存在 - Linux/macOS 下注意 SELinux 或 sandbox 权限(如 macOS 的 Full Disk Access)
大文件拷贝时别忽略 gcount() 和 failbit
用 read() 读取后,实际读到的字节数不一定等于请求长度,尤其在文件末尾;而 failbit 可能因磁盘满、I/O 中断等触发,但流对象仍可继续用——得手动清标志再判状态。
- 每次
read()后必须调gcount()获取真实读取字节数,不能假设填满缓冲区 - 循环里不要只靠
!src.eof()判断——eofbit是读后才置位,容易多读一次 - 如果
write()后!dst.good(),要立刻检查dst.failbit(磁盘满)还是dst.badbit(硬件故障) - 拷贝中途出错时,目标文件可能已部分写入,需主动
dst.close()并删除残片
C++17 起用 std::filesystem::copy 更省心但有坑
它封装了底层逻辑,支持递归、跳过同名文件、保留时间戳等,但默认行为和直觉不符。
立即学习“C++免费学习笔记(深入)”;
- 默认不覆盖已有文件,会抛
std::filesystem::filesystem_error,得加std::filesystem::copy_options::overwrite_existing - 不处理跨文件系统硬链接,复制后变成普通文件;软链接则默认被解引用(内容被拷贝),不是复制链接本身
- 某些旧 libc++ 实现(如 macOS 10.15 自带)对中文路径支持不全,建议升级编译器或回退到流方式
- 性能未必更好:内部仍是分块读写,但多了路径解析和属性操作开销
简单场景够用,但需要精确控制或兼容老环境时,手写流更可靠。
真正麻烦的是错误恢复——比如拷贝中电源中断,源文件完好但目标文件损坏,这时候没有原子性保证,得靠上层加校验或事务日志。流方式至少让你清楚每一步卡在哪。











