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

std::filesystem::directory_iterator遇西里尔字母失效问题排查

问题根源与解决方案

核心问题:Windows下的字符编码不匹配

程序崩溃是因为Windows系统中,包含西里尔字母的路径属于Unicode字符集,但你的代码全程使用窄字符(char/std::string)处理路径,导致编码转换失败,触发未定义行为。具体触发点包括:

  • 命令行参数通过char* argv[]接收,无法识别西里尔字母这类非ANSI字符,导致路径构造错误;
  • 调用entry.path().filename().string()将Unicode路径转窄字符时,非代码页字符会被转成无效值,后续路径拼接操作出错;
  • std::ofstream默认是窄字符流,写入西里尔字母时会出现编码异常,甚至导致流操作失败。

需要处理的技术点与修复方案

1. 改用宽字符接收命令行参数

Windows下替换main为wmain,直接获取Unicode格式的命令行参数,避免编码丢失:

#define UNICODE
#define _UNICODE

#include <filesystem>
#include <fstream>
#include <stdio.h>
#include <locale>
#include <codecvt>

namespace fs = std::filesystem;
std::wstring dirList[100];
std::wofstream fp;
void DisplayPath(const fs::path&, int); 

int wmain(int argc, wchar_t* argv[])
{
    if (argc < 3) { wprintf(L"fSDI.exe <startPath> <outFile>\n"); exit(0); }
    const fs::path toRetrieve(argv[1]);
    std::wstring out(argv[2]);
    
    // 初始化宽字符输出流,设置UTF-8编码确保西里尔字母正确写入
    fp.open(out, std::ios::out);
    fp.imbue(std::locale(fp.getloc(), new std::codecvt_utf8<wchar_t>));
    
    fp << L"retrieve: " << toRetrieve << std::endl;
    dirList[0] = fs::absolute(toRetrieve).wstring();
    DisplayPath(toRetrieve, 0);
    fp.close();
    return 0;
}

2. 全程用宽字符串存储路径组件

将dirList和路径相关字符串全部改为std::wstring,避免窄字符转换丢失信息:

std::wstring dirList[100];
std::wofstream fp;

3. 更新路径遍历与拼接逻辑

修改DisplayPath函数,所有路径操作使用宽字符,同时修正原代码中路径拼接的错误逻辑:

void DisplayPath(const fs::path& pathToScan, int lv = 0)
{
    for (const auto& entry : fs::directory_iterator(pathToScan))
    {
        const auto file = entry.path().filename().wstring();
        if (entry.is_directory())
        {
            fp << L"[" << entry.path().filename().wstring() << L"]" << std::endl;
            dirList[lv+1] = entry.path().filename().wstring();
            DisplayPath(entry, lv + 1);
        }
        else if (entry.is_regular_file())
        {
            std::wstring fullPath = dirList[0];
            // 修正根路径的拼接判断逻辑
            if (!(dirList[0].size() == 3 && dirList[0][1] == L'\\'))
                fullPath += L"\\";
            for(int i=1;i<=lv;i++) fullPath += dirList[i] + L"\\";
            fp << L" " << fullPath << file << std::endl;
        }
    }
}

4. 启用编译器Unicode支持

在Windows项目设置中开启Unicode字符集(而非多字节字符集),或者在代码开头定义UNICODE和_UNICODE宏,确保系统API调用使用宽字符版本。

关键原理补充

  • std::filesystem::path在Windows内部以宽字符存储路径,但如果用窄字符构造,会依赖当前系统代码页转换,非代码页字符会直接丢失;
  • 宽字符流std::wofstream配合codecvt_utf8转换器,可将Unicode字符以UTF-8编码写入文件,保证西里尔字母能正确保存和读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:50:26