You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ReadFile读取文件后打印出现异常字符的问题排查

问题描述

我有一个内容为"SakyLabs. Hello, MDE"的纯文本文件,尝试使用ReadFile函数读取后打印,却得到如下输出:

?SakyLabs. Hello, MDE??²

请问我哪里操作出错了?

以下是我的代码:

// 用于CreateFileW
HANDLE createFile;  
DWORD fileDesiredAccess = GENERIC_READ | GENERIC_WRITE;
DWORD fileShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD creationDisposition = CREATE_ALWAYS;
DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;

// ReadFile函数相关变量
BOOL readFile;
DWORD lastError;
DWORD fileSize;
LPWSTR fileBuffer;
DWORD bytesRead;

if ((wcscmp(argv[1], L"-ef") == 0))
{
    createFile = CreateFileW(argv[2], fileDesiredAccess, fileShareMode, NULL, OPEN_EXISTING, fileFlags, NULL);

    // 获取扩展错误信息
    lastError = GetLastError();

    if (createFile == INVALID_HANDLE_VALUE)
    {
        wprintf(L"打开文件出错,错误码:%d ", lastError);
        ShowErrorMessage(lastError);
        return;
    }

    // 文件已打开!读取内容

    fileSize = GetFileSize(createFile, NULL);

    fileBuffer = (LPWSTR)malloc((fileSize) + 1);

    if (fileBuffer == NULL)
    {
        wprintf(L"内存分配失败。\n");
        CloseHandle(createFile);
        return;
    }

    readFile = ReadFile(createFile, fileBuffer, fileSize, &bytesRead, NULL);
    lastError = GetLastError();

    if (!readFile)
    {
        wprintf(L"读取文件出错,错误码:%d ", lastError);
        ShowErrorMessage(lastError);
        CloseHandle(createFile);
        return;
    }

    fileBuffer[fileSize] = '\0';

    // 显示内容
    wprintf(L"%s \n", fileBuffer);
    free(fileBuffer);
    CloseHandle(createFile);
}

return 0;
}
问题原因及解决方法

核心问题是文本编码不匹配,同时存在内存分配和字符串终止的错误:

具体错误点

  • 编码不匹配:纯文本文件默认是ANSI或UTF-8(单字节/可变字节编码),但你用LPWSTR(对应UTF-16双字节宽字符)存储读取的原始字节,并用wprintf(宽字符输出函数)打印,导致单字节数据被强行解析为双字节UTF-16,出现乱码。
  • 内存分配错误:LPWSTR每个字符占2字节,你按文件字节数fileSize分配内存,再加1个单字节空间,既不符合宽字符内存需求,也会导致内存不足。
  • 字符串终止错误:fileBuffer[fileSize] = '\0';中fileSize是字节数,但LPWSTR的索引是按字符数(每个2字节),导致终止符位置错误,引发越界或无效宽字符。
  • 错误码调用时机错误:CreateFileW成功后仍调用GetLastError,会覆盖原本的0值或残留之前的错误码,应该只在createFile == INVALID_HANDLE_VALUE时调用。

解决方法(二选一)

方法1:使用ANSI字符集处理(适合普通纯文本)

将宽字符相关类型和函数替换为ANSI版本,匹配普通纯文本的编码:

// 修改变量类型
LPSTR fileBuffer;
// ...
// 内存分配按字节数+1
fileBuffer = (LPSTR)malloc(fileSize + 1);
// ...
// 用实际读取的字节数设置终止符
fileBuffer[bytesRead] = '\0';
// 用ANSI输出函数
printf("%s \n", fileBuffer);

方法2:UTF-8转UTF-16处理(推荐,支持多语言)

如果文件是UTF-8编码,先读取原始字节流,再转换为UTF-16宽字符后输出:

// 读取UTF-8原始字节
LPSTR utf8Buffer = (LPSTR)malloc(fileSize + 1);
ReadFile(createFile, utf8Buffer, fileSize, &bytesRead, NULL);
utf8Buffer[bytesRead] = '\0';

// 计算需要的宽字符缓冲区大小
int wcharSize = MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, NULL, 0);
LPWSTR wcharBuffer = (LPWSTR)malloc(wcharSize * sizeof(WCHAR));
// 转换为UTF-16
MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, wcharBuffer, wcharSize);

// 输出宽字符内容
wprintf(L"%s \n", wcharBuffer);

// 释放内存
free(utf8Buffer);
free(wcharBuffer);

额外注意事项

  • 读取文件时优先使用bytesRead(实际读取字节数)而非fileSize,避免因文件系统或权限问题导致读取不完整。
  • 调用GetLastError必须紧跟在失败的API调用之后,否则错误码会被后续操作覆盖。

内容的提问来源于stack exchange,提问作者Sergio Calderon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:30:46