std::wifstream 无法直接读取 euc-jp 文件,因标准库不支持该编码且 codecvt 已弃用;应先用 std::ifstream 二进制读取,再用 iconv 转为 utf-8。

用 std::wifstream 直接读取 EUC-JP 文件会失败
标准 C++ 流(包括 std::wifstream)默认不识别 EUC-JP,即使设置了 locale 也大概率读成乱码或空内容。根本原因是 C++ 标准库的 facet(如 std::codecvt_utf8)不支持 EUC-JP,且多数平台(Linux/macOS 的 glibc、Windows 的 MSVC)根本不提供 EUC-JP 的 std::codecvt 实现——调用会触发 std::runtime_error 或静默失败。
推荐方案:先用字节流读入,再用 iconv 转码为 UTF-8
这是最可靠、跨平台性最好的做法。核心思路是绕过 C++ iostream 的编码层,用 std::ifstream 以二进制模式读取原始字节,再交给成熟的转码库处理。
- Linux/macOS:系统自带
iconv,头文件为<iconv.h></iconv.h>,链接-liconv(macOS 可能无需显式链接) - Windows:可用
libiconv(MinGW 或 vcpkg 安装),或用 Windows API 的MultiByteToWideChar(CP_EUCJP)(但注意 CP_EUCJP 并非 Windows 原生代码页,需确认系统是否支持;更稳妥仍选 libiconv) - 转码目标建议统一为 UTF-8:
std::string存储,避免宽字符和 locale 依赖
示例关键片段(Linux/macOS):
std::ifstream file("data.txt", std::ios::binary);
std::vector<char> bytes((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
iconv_t cd = iconv_open("UTF-8", "EUC-JP");
// ... 分配输出缓冲区、调用 iconv()、错误检查 ...
iconv_close(cd);
// result 是 UTF-8 编码的 std::string
</char></char></char>
如果坚持用 C++ iostream + locale,必须自己实现 codecvt(不推荐)
理论上可继承 std::codecvt<char32_t char std::mbstate_t></char32_t> 并实现 do_in/do_out,但实际非常危险:
- EUC-JP 是变长编码(1~3 字节),状态管理极易出错;单个字节
0xA1–0xFE可能是 ASCII 扩展,也可能是多字节序列起始,需完整上下文判断 - C++17 已弃用
std::codecvt,MSVC 早已移除,GCC/Clang 仅保留但标记为 deprecated,未来标准可能彻底删除 - 没有现成可靠的开源实现;网上零星代码多有边界 case 漏判(如混入 ISO-2022-JP 转义序列时崩溃)
读取后字符串处理务必注意编码语义
即使成功转成 UTF-8,后续操作仍要小心:
- 用
std::string::length()得到的是字节数,不是字符数;日文汉字/假名在 UTF-8 中占 3 字节,substr(0, 5)可能截断一个字符 - 正则匹配(
std::regex)默认按字节而非 Unicode 码点工作,对日文基本无效;应改用 ICU 或 C++20 的<regex></regex>(若编译器支持 Unicode-aware 模式) - 写回文件时,别误用
std::ofstream默认 locale 输出——它不会自动加 BOM,且可能把 UTF-8 当作 Latin-1 写出乱码;明确以二进制模式写,并确保内容确实是 UTF-8 字节
EUC-JP 的坑不在“怎么读”,而在“读完之后你以为它是普通字符串”——所有基于字节长度、字节比较、默认 locale 的操作,都可能在日文文本上突然失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











