c++ 有没有一个函数可以获取Windows上文件的真实、区分大小写的路径?

vd2z7a6w  于 4个月前  发布在  Windows
关注(0)|答案(1)|浏览(71)

我正在为一个游戏创建std::filesystem Lua绑定,我想确保稍后使用绑定的mod不依赖于Windows的大小写不敏感性。
例如,在Windows上,fopen("foo.txt", "w")后跟fopen("Foo.txt", "r")读取文件,而在Linux上则不会,因为Linux是区分大小写的。这不仅涉及文件名,而且涉及整个路径,因为假设bar/存在,fopen("bar/baz.txt", "w")后跟fopen("Bar/baz.txt", "r")在Windows上工作,但在Linux上也会失败。因此,尽管mod可能在Windows上工作,它会破坏Linux用户,我想防止。
以前,我通过使用这里的代码“使”Linux不区分大小写来解决这个问题,这实际上是通过迭代目录中的所有条目并检查名称是否不区分大小写地匹配来构建向上的路径,每次一个父目录。
这个解决方案的代码不是很优雅,而且相当大,但是,现在我已经决定,我想做的恰恰相反,“使”Windows是大小写敏感的,我希望也许有一些功能,我可以在Windows上使用,以获得一个文件的真正的大小写敏感的路径,使fopen("Foo.txt", "r")将失败的 * 两个 * 操作系统。
我已经在谷歌上搜索了很多,并期待着任何其他人谁问过这个问题,但大多数答案要么是咆哮“为什么会有人需要它”,或者做我目前的解决方案,我上面链接的等价物。
例如,我尝试使用GetFullPathName(),将其放入foo.cpp文件中,但它打印C:\Users\<user>\Desktop\Foo.cpp,所以没有用,因为我需要Foo.cpp与实际文件名相同:

#include <iostream>
#include <windows.h>

int main() {
    char filename[] = "Foo.cpp";
    char fullFilename[MAX_PATH];

    GetFullPathName(filename, MAX_PATH, fullFilename, nullptr);
    std::cout << fullFilename << std::endl;
}

字符串
谢谢

tzcvj98z

tzcvj98z1#

策略是打开文件并检索实际打开的文件路径(使用GetFinalPathNameByHandle):

struct HandleCloser {
    HANDLE h;
    ~HandleCloser() { ::CloseHandle(h); }
};

std::wstring final_path(const wchar_t* file_name) {
    HANDLE fp = ::CreateFileW(
        /*lpFileName=*/file_name,
        /*dwDesiredAccess=*/0,
        /*dwShareMode=*/FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
        /*lpSecurityAttributes=*/nullptr,
        /*dwCreationDisposition=*/OPEN_EXISTING,
        /*dwFlagsAndAttributes=*/FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,
        /*hTemplateFile=*/nullptr);
    // (FILE_FLAG_BACKUP_SEMANTICS to work on directories and
    // FILE_FLAG_OPEN_REPARSE_POINT to work on symlinks)
    if (fp == INVALID_HANDLE_VALUE) {
        // Handle error...
        return {};
    }
    HandleCloser _{fp};
    std::wstring result;
    result.resize(MAX_PATH);
    DWORD size = ::GetFinalPathNameByHandleW(
        fp, result.data(), result.size() + 1u, FILE_NAME_NORMALIZED
    );
    if (size > result.size()) {
        result.resize(size);
        size = ::GetFinalPathNameByHandleW(
            fp, result.data(), result.size() + 1u, FILE_NAME_NORMALIZED
        );
    }
    if (size == 0) {
        // Handle error...
        return {};
    }
    result.resize(size);
    return result;
}

字符串
不要使用FILE_FLAG_POSIX_SEMANTICS打开文件是很重要的,因为这样不区分大小写的路径转换就不会发生。你不需要对文件有读/写权限。如果路径不存在,这将失败,在这种情况下,你可能想遍历子目录,看看它们是否在正确的大小写。
我认为这也是std::filesystem::canonical对Microsoft STL所做的。
或者,您可以在Windows上实现Lua fopen以使用FILE_FLAG_POSIX_SEMANTICS打开。这将不允许您在写入foo.txt时读取Foo.txt,并允许您拥有两个不同的文件Foo.txtfoo.txt,即使在Windows上也是如此。

相关问题