如何将ToUnicodeEx()生成的UCS-2 LE编码内容转换为UTF-8?
如何将UCS-2 LE编码的键盘记录文件转换为UTF-8?
我来帮你解决这个编码转换的问题~你现在的情况是用GetAsyncKeyState()捕获输入,通过ToUnicodeEx()转成宽字符后,用wfstream写入了UCS-2 LE编码的文件,想要转成UTF-8对吧?有两种思路,一种是在写入的时候直接输出UTF-8(这是更推荐的方式,避免后续转换),另一种是把已有的UCS-2 LE文件转换成UTF-8,我给你详细说说:
一、写入时直接输出UTF-8(推荐)
wfstream在Windows环境下默认会按UCS-2/UTF-16 LE编码写入文件,所以我们可以改用普通的字节流输出(std::ofstream),先把宽字符转换成UTF-8字节序列再写入。
实现步骤:
- 使用Windows API的
WideCharToMultiByte()函数,将wchar_t类型的字符转换为UTF-8编码的字节数组。 - 用
std::ofstream以二进制模式打开文件,先写入UTF-8的BOM(0xEF 0xBB 0xBF),再写入转换后的UTF-8字节。
代码示例:
#include <windows.h> #include <fstream> #include <string> // 把宽字符转换为UTF-8字符串 bool WideCharToUtf8(const wchar_t* wideChar, std::string& utf8Str) { if (!wideChar) return false; // 计算需要的UTF-8字节数 int requiredSize = WideCharToMultiByte( CP_UTF8, // 指定转换为UTF-8 0, // 无特殊标志 wideChar, // 输入的宽字符 -1, // 自动处理末尾的null终止符 nullptr, // 暂不输出,先计算长度 0, nullptr, nullptr ); if (requiredSize == 0) return false; utf8Str.resize(requiredSize - 1); // 减去末尾的null字符 WideCharToMultiByte( CP_UTF8, 0, wideChar, -1, &utf8Str[0], requiredSize, nullptr, nullptr ); return true; } int main() { // 假设你已经通过ToUnicodeEx获取到了character[0] wchar_t character[1] = {L'A'}; // 示例字符 // 打开文件准备写入UTF-8 std::ofstream logFile("key_log_utf8.txt", std::ios::binary); if (logFile.is_open()) { // 写入UTF-8 BOM,让编辑器正确识别编码 const char utf8Bom[] = {0xEF, 0xBB, 0xBF}; logFile.write(utf8Bom, sizeof(utf8Bom)); // 转换为UTF-8并写入 std::string utf8Char; if (WideCharToUtf8(character, utf8Char)) { logFile.write(utf8Char.c_str(), utf8Char.size()); } logFile.close(); } return 0; }
二、转换已有的UCS-2 LE文件为UTF-8
如果已经有了现成的UCS-2 LE文件,你可以选择两种方式转换:
方式1:用Notepad++手动转换
打开文件后,点击顶部菜单的编码 → 转为UTF-8(或者转为UTF-8无BOM,根据你的需求选择),然后保存即可。这种方式适合少量文件的快速转换。
方式2:用代码批量转换
如果需要批量处理文件,可以通过代码读取UCS-2 LE内容,转换为UTF-8后写入新文件:
#include <windows.h> #include <fstream> #include <vector> #include <string> bool ConvertUcs2LeToUtf8(const std::string& inputPath, const std::string& outputPath) { // 读取UCS-2 LE文件(二进制模式) std::ifstream inputFile(inputPath, std::ios::binary); if (!inputFile.is_open()) return false; // 读取所有字节 std::vector<char> inputBytes( (std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>() ); inputFile.close(); // 跳过UCS-2 LE的BOM(0xFF 0xFE)如果存在 size_t startPos = 0; if (inputBytes.size() >= 2 && inputBytes[0] == 0xFF && inputBytes[1] == 0xFE) { startPos = 2; } // 将字节转换为宽字符(UCS-2 LE就是小端UTF-16) std::wstring wideContent( reinterpret_cast<const wchar_t*>(&inputBytes[startPos]), (inputBytes.size() - startPos) / sizeof(wchar_t) ); // 转换为UTF-8 int utf8Size = WideCharToMultiByte( CP_UTF8, 0, wideContent.c_str(), -1, nullptr, 0, nullptr, nullptr ); if (utf8Size == 0) return false; std::string utf8Content(utf8Size - 1, '\0'); WideCharToMultiByte( CP_UTF8, 0, wideContent.c_str(), -1, &utf8Content[0], utf8Size, nullptr, nullptr ); // 写入UTF-8文件(带BOM) std::ofstream outputFile(outputPath, std::ios::binary); if (!outputFile.is_open()) return false; const char utf8Bom[] = {0xEF, 0xBB, 0xBF}; outputFile.write(utf8Bom, sizeof(utf8Bom)); outputFile.write(utf8Content.c_str(), utf8Content.size()); outputFile.close(); return true; } // 使用示例 // ConvertUcs2LeToUtf8("old_ucs2le_log.txt", "new_utf8_log.txt");
补充说明
你之前写入0xFEFF是UCS-2 LE的BOM,所以Notepad++会识别为UCS-2 LE编码。而UTF-8的标准BOM是0xEF 0xBB 0xBF,写入它可以让编辑器正确识别文件为UTF-8编码。
内容的提问来源于stack exchange,提问作者Alexander T. Haselton
相关产品推荐
相关产品推荐

