Winapi 在windows上获取文件系统中的路径的有效方法

Winapi 在windows上获取文件系统中的路径的有效方法,winapi,filesystems,Winapi,Filesystems,Windows文件系统不区分大小写。当我有一个文件路径时,我希望案例与文件系统中的情况完全相同。现在,我正在使用以下代码来确保这一点: std::vector<std::wstring> directories; boost::split(directories, api, is_any_delimiter); size_t i = 0; std::wstring path; if (hasWindowsDriverLetter()) { path += director

Windows文件系统不区分大小写。当我有一个文件路径时,我希望案例与文件系统中的情况完全相同。现在,我正在使用以下代码来确保这一点:

std::vector<std::wstring> directories;
boost::split(directories, api, is_any_delimiter);

size_t i = 0;
std::wstring path;

if (hasWindowsDriverLetter())
{
    path += directories[i++];
}

std::wstring delimiter(L"\\");

for (;i < directories.size(); ++i)
{
    std::wstring search = path + delimiter + directories[i];

    WIN32_FIND_DATAW FindFileData;
    HANDLE hFind = FindFirstFileW(search.c_str(), &FindFileData);
    if (hFind == INVALID_HANDLE_VALUE)
    {
        path = search;
        continue;
    }

    path += delimiter + FindFileData.cFileName;
    ::FindClose(hFind);
}
我的职能是在性能敏感的地方-有没有更有效的方法来做到这一点


注意:GetLongPathNameW不起作用。

尝试以下方法:

std::wstring::iterator GetIteratorAfterRoot(std::wstring &str)
{
    std::wstring::iterator iter = str.begin();

    wchar_t *tmp = str.c_str();
    wchar_t *tmp2;
    if (PathCchSkipRoot(tmp, &tmp2) == S_OK)
        iter += std::distance(tmp, tmp2);

    return iter;
}

如果您知道Windows不关心原始的大小写,那么为什么需要这个呢?因为我需要路径的文本表示形式为字符串,并且我使用它来识别另一个区分大小写的系统中的文件。您无法加快FindFirstFile的速度,但您可以通过不使用拆分或动态构建新路径来加快其余代码的速度。而是直接迭代原始api路径。每次遇到分隔符时,请临时将其替换为\0,并使用原始api字符串调用FindFirstFile,然后还原该分隔符并使用找到的结果替换该分隔符和最后一个分隔符之间的所有内容。只要大小写更改不会导致大小不同的子字符串,您就不需要执行任何内存分配。如果查找到文件,请停止搜索,因为从此以后将无法获得任何进一步的结果。为什么不以不区分大小写的方式跟踪文件,或者在跟踪文件之前将其转换为普通大小写?
std::wstring api = ...;

std::wstring start = GetIteratorAfterRoot(api);
std::wstring end = api.end();

WIN32_FIND_DATAW FindFileData;
HANDLE hFind;

bool finished = false;
while (start != end)
{
    std::wstring::iterator found = std::find_if(start, end, is_any_delimiter); 

    if (found != end)
    {
        wchar_t delim = *found;
        *found = L'\0';
        hFind = FindFirstFileW(api.c_str(), &FindFileData);
        *found = delim;
    }
    else
    {
        finished = true;
        hFind = FindFirstFileW(api.c_str(), &FindFileData);
    }

    if (hFind != INVALID_HANDLE_VALUE)
    {
        ::FindClose(hFind);

        std::wstring::difference_type SearchLength = std::distance(start, found);
        int FileNameLength = lstrlenW(FindFileData.cFileName);

        if (SearchLength != FileNameLength)
        {
            // string length is changing...

            if (finished)
            {
                api.replace(start, found, FindFileData.cFileName);
                break;
            }

            std::wstring::difference_type SearchOffset = std::distance(api.begin(), start);
            api.replace(start, found, FindFileData.cFileName);
            start = api.begin() + (SearchOffset + FileNameLength + 1);
            end = api.end();

            continue;
        }

        // string length not changing, copy new name inlined...

        // not sure if std::wstring::replace() is smart enough to do an
        // inline copy if the two lengths match, so using std::copy instead...

        //api.replace(start, found, FindFileData.cFileName); 
        std::copy(FindFileData.cFileName, &FindFileData.cFileName[FileNameLength], start); 
    }

    if (finished)
        break;

    start = found + 1;
}