MSVC下std::filesystem::path转字符串/打印时字符映射错误求助
问题描述
- 用VS2022写的C++目录遍历代码,碰到文件名
FM_(`・ω・´)シャキーン1(1秒).ogg时直接触发运行时abort - 抛出异常:在多字节的目标代码页中,没有此Unicode字符可以映射到的字符,调用
fp.string()时也会触发这个异常 - 只有打印文件名的时候出问题,删掉
DEBUG_MSG( fp );后程序完全正常 - 试了
wcout+wstring没异常,但输出直接截断;用.u8string()输出全是乱码
相关代码
void rena::HUFO::_traversal_dir_write_to_hlist( const std::filesystem::path& dir ){ for ( auto it : std::filesystem::directory_iterator( dir ) ) { auto fp = it.path(); // file path if ( std::filesystem::is_directory( fp ) ) { _traversal_dir_write_to_hlist( fp ); } // dir found, traversal it else { if ( fp == this -> _hufopath ) { continue; } // ignore HUFO itself DEBUG_MSG( fp ); HASHOBJ temp; temp.fp = std::filesystem::relative( fp , this -> _pdpath ); this -> _hlist.push_back( temp ); } // write relative path to _hlist } return; }
尝试输出情况
使用cout+string(捕获异常)
"...\camera.wav" Error occured when traversaling directory "...": 在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。 Error path output unavaliable. Skip the current file. "...\FM_アイテムゲット11(1秒).ogg" "...\FM_アイテムゲット2(1秒).ogg" "...\FM_アイテムゲット3(1秒).ogg" ... (other files)
使用wcout+wstring
"...\camera.wav" "...\FM_(
问题原因
string()编码转换失败:Windows默认用多字节代码页(比如GBK),但这个编码覆盖不了所有Unicode字符,碰到文件名里的`・ω・´シャキーン这类不在当前代码页的字符,转换直接报错。wcout输出截断:控制台默认编码不是UTF-16,wcout碰到显示不了的字符或者编码不匹配时,会直接中断输出,导致内容截断。.u8string()乱码:控制台没设成UTF-8编码,解析不了UTF-8字节流,自然显示乱码。
解决方法
方法一:控制台设为UTF-8编码(推荐)
在程序开头加这段代码,把控制台编码改成UTF-8,然后用u8string输出:
#include <Windows.h> // 配置控制台输入输出为UTF-8 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); // 输出时调用u8string DEBUG_MSG(fp.u8string());
注意:VS2022项目属性里,把常规->字符集设为「使用多字节字符集」或者「未设置」,才能保证
u8string正常输出。
方法二:修复wcout截断问题
配置控制台支持UTF-16,同时关掉wcout的异常触发机制:
#include <iostream> #include <Windows.h> // 设置控制台为UTF-16输出 SetConsoleOutputCP(CP_UTF16); // 取消wcout的异常掩码,碰到显示不了的字符也不中断输出 std::wcout.exceptions(std::ios_base::goodbit); // 输出宽字符路径 DEBUG_MSG(fp.wstring());
部分特殊字符可能还是显示不出来,但不会截断或报错,路径本身是完整的。
方法三:用Windows原生API输出
如果上面两种方法都不行,直接调用Windows API输出宽字符:
#include <Windows.h> // 自定义输出宽字符路径的函数 void DebugPrintPath(const std::filesystem::path& path) { const wchar_t* wstr = path.c_str(); WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wstr, wcslen(wstr), nullptr, nullptr); std::wcout << L"\n"; } // 替换原DEBUG_MSG调用 DebugPrintPath(fp);
内容的提问来源于stack exchange,提问作者Ace_Radom
相关产品推荐
相关产品推荐

