CFile二进制读写必须显式指定CFile::typeBinary标志,否则可能触发文本模式换行转换;Read()返回实际字节数而非成功标志,需结合GetLastError()判断错误;大文件应分块读取并避免裸内存管理。

用 CFile 以二进制模式打开文件必须显式指定 CFile::typeBinary
默认情况下,CFile 构造或 Open() 时若只传 CFile::modeRead,在 MFC 内部仍可能触发文本模式换行转换(尤其在旧版 CRT 兼容逻辑下),导致读到的 \r\n 被悄悄转成 \n,破坏原始字节流。这不是 bug,而是历史行为残留。
正确做法是:无论读还是写,只要目标是二进制数据,就必须组合 CFile::typeBinary 标志:
CFile file;
if (file.Open(_T("data.bin"), CFile::modeRead | CFile::typeBinary))
{
// 安全读取原始字节
}-
CFile::typeBinary必须与modeRead或modeWrite同时使用,单独传无效 - Unicode 工程中路径用
_T()包裹,避免LPCTSTR类型误判 - 不检查返回值直接操作
file会导致访问违规——Open()失败后对象处于未初始化状态
Read() 返回值不是“是否成功”,而是“实际读取字节数”
CFile::Read(void* lpBuf, UINT nCount) 的返回值类型是 UINT,它从不抛异常,也不返回 -1 表示失败;它只告诉你本次调用从文件中拷贝了多少字节到缓冲区。遇到 EOF、磁盘错误或部分读取时,它都只返回小于 nCount 的数——包括 0。
这意味着不能靠“返回值是否等于 nCount”来断定读完全部数据,更不能当成布尔成功标志:
立即学习“C++免费学习笔记(深入)”;
char buf[1024];
UINT nRead = file.Read(buf, sizeof(buf));
if (nRead == 0) {
// 可能是 EOF,也可能是磁盘已满、权限不足等 I/O 错误
DWORD dwErr = ::GetLastError(); // 需要查系统错误码
}- 每次读取后应调用
::GetLastError()判断真实原因,例如ERROR_HANDLE_EOF或ERROR_ACCESS_DENIED - 循环读取时,必须把
nRead > 0作为继续条件,而非nRead == sizeof(buf) - 缓冲区大小建议为 4KB 或其整数倍,避开底层 NTFS / FAT32 的簇对齐问题,减少小块读取开销
MFC 的 CFile 不自动处理 Unicode BOM,读写 UTF-8/UTF-16 文件需手动跳过或写入
CFile 是纯字节搬运工,对文本编码零感知。如果你用它读一个带 UTF-8 BOM(0xEF, 0xBB, 0xBF)的文件,这三个字节会原样进入缓冲区;同理,写入前不手动插入 BOM,外部程序就无法识别编码。
常见误操作是:用 CString 接收 Read() 结果后直接 MessageBox(),结果中文显示乱码——其实是因为没剥离 BOM 或没按对应编码 reinterpret_cast。
- 读取 UTF-8 文件时,先读 3 字节判断是否为 BOM,再决定后续解码起点
- 写入 UTF-8 文件前,如需兼容 Notepad,应先
Write("\xEF\xBB\xBF", 3),再写正文 - 不要试图用
CFile+CString::LoadString()混用——后者内部走 Win32LoadStringAPI,依赖资源节,和文件 I/O 无关
大文件读取慎用单次 Read(),MFC 默认缓冲区不启用,需自行管理内存
CFile 本身不提供内置缓冲(不像 CStdioFile 那样封装了 FILE* 缓冲机制),每次 Read() 几乎都对应一次 Win32 ReadFile() 系统调用。对几百 MB 的文件,一次性申请大内存并单次读取,既浪费虚拟地址空间,又容易触发 std::bad_alloc(尤其在 32 位 MFC 程序中)。
- 推荐分块读取:每次
Read()4KB~64KB,视数据局部性而定 - 用
std::vector<byte></byte>替代裸new BYTE[],避免忘记delete[]导致泄漏 - 若需随机访问大文件,优先考虑
CreateFileMapping()+MapViewOfFile(),比反复Seek()+Read()快一个数量级
真正麻烦的从来不是怎么读,而是读错了还不知道错在哪——比如 BOM 当内容、EOF 当错误、缓冲区溢出盖掉邻近变量。这些点不写死在代码注释里,下次维护时大概率重踩一遍。


















