使用std::filesystem递归遍历目录时遇Unicode转换异常1113的问询
解决std::filesystem::recursive_directory_iterator遍历含特殊Unicode字符文件的异常问题
问题现象
- 使用
std::filesystem::recursive_directory_iterator遍历目录时触发异常,设置directory_options::skip_permission_denied无法解决 - 删除当前触发异常的文件后,异常会随机出现在其他文件;不删除该文件则每次遍历都会在该文件处触发
- 在Visual Studio中点击三次继续按钮后,程序可恢复遍历
测试代码(简化后):
#define NOMINMAX #include <string> #include <iostream> #include <filesystem> #include <windows.h> #include <fstream> #include <winbase.h> #include <numeric> #include <string_view> #include <vector> #include <shlobj_core.h> //#include <combaseapi.h> namespace fs = std::filesystem; using namespace std; void startWinXSearch(string argv) { string pathToFolder = argv; cout << pathToFolder << endl; for (auto& el : std::filesystem::recursive_directory_iterator(pathToFolder, std::filesystem::directory_options::skip_permission_denied)) { cout << el << endl; } } int main(int argc, char* argv[]) { CoInitializeEx(NULL, COINIT_MULTITHREADED); string test = "C:\\Sciebo"; startWinXSearch(test); }
排查过程
改用wcout输出后,得到明确错误信息:"No mapping for the Unicode character exists in the target multi-byte code page",最终定位到异常原因是目录中存在来自手机的文件,文件名包含无法映射到当前系统多字节代码页的隐形Unicode字符。
解决方案/规避方案
1. 全链路使用宽字符支持Unicode
将代码中的std::string替换为std::wstring,cout替换为wcout,确保路径处理和输出都支持完整Unicode字符集:
#define NOMINMAX #include <wstring> #include <iostream> #include <filesystem> #include <windows.h> #include <fstream> #include <winbase.h> #include <numeric> #include <string_view> #include <vector> #include <shlobj_core.h> namespace fs = std::filesystem; using namespace std; void startWinXSearch(wstring argv) { wstring pathToFolder = argv; wcout << pathToFolder << endl; for (auto& el : std::filesystem::recursive_directory_iterator(pathToFolder, std::filesystem::directory_options::skip_permission_denied)) { wcout << el.path() << endl; } } int main(int argc, char* argv[]) { CoInitializeEx(NULL, COINIT_MULTITHREADED); wstring test = L"C:\\Sciebo"; startWinXSearch(test); }
2. 捕获编码异常并跳过
在遍历和输出过程中添加异常捕获,针对编码相关错误直接跳过,保证遍历流程不中断:
void startWinXSearch(wstring argv) { wstring pathToFolder = argv; wcout << pathToFolder << endl; try { for (auto& el : std::filesystem::recursive_directory_iterator(pathToFolder, std::filesystem::directory_options::skip_permission_denied)) { try { wcout << el.path() << endl; } catch (const std::exception& e) { wcerr << L"输出文件路径失败: " << e.what() << endl; continue; // 跳过该文件,继续遍历 } } } catch (const std::filesystem::filesystem_error& e) { wcerr << L"遍历目录失败: " << e.what() << endl; } }
3. 清理特殊字符文件
手动排查或通过文件搜索工具找到来自手机同步的含隐形Unicode字符的文件,重命名为合法名称或直接删除,从根源消除异常触发点。
内容的提问来源于stack exchange,提问作者Gisbert12843
相关产品推荐
相关产品推荐

