从表示 Windows 上的任意文件名的 QString 获取 std::string 或 C 字符串

Getting a std::string or C string from a QString representing an arbitrary filename on Windows

我正在使用 QFileDialog::getOpenFileName() 让用户 select 一个文件,但我需要结果是一个 C 字符串,因为我必须将它传递给用 C 编写的东西,它使用fopen()。我不能改变这个。

我发现的问题是,在 Windows/MinGW 上,对结果 QString 使用 toStdString() 不能很好地处理 Unicode/non-ASCII 文件名。尝试打开基于 std::string 的文件失败,因为某些字符集转换似乎正在发生。有时使用 toLocal8Bit() 转换有效,但有时无效。

考虑以下 (MinGW) 程序:

#include <cstdio>
#include <iostream>

#include <QApplication>
#include <QFileDialog>
#include <QFile>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    auto filename = QFileDialog::getOpenFileName();
    QFile f(filename);

    std::cout << "fopen: " << (std::fopen(filename.toStdString().c_str(), "r") != nullptr) << std::endl;
    std::cout << "fopen (local8bit): " << (std::fopen(filename.toLocal8Bit().data(), "r") != nullptr) << std::endl;
    std::cout << "Qt can open: " << f.open(QIODevice::ReadOnly) << std::endl;
}

不过,在所有情况下,QFile 都可以打开文件。我想它可能使用 Unicode Windows 函数,而 C 代码使用 fopen(),据我了解,这是 Windows 上的所谓 ANSI 函数。但是有没有什么办法可以从 QString 中得到一个“字节袋”呢?我不关心文件名的编码,我只想要一些可以传递给 fopen() 来打开文件的东西。

我发现使用 GetShortPathNamefilename.toWCharArray() 获取短文件名似乎可行,但这非常麻烦,我的理解是 NTFS 文件系统可以被告知不支持短文件名名称,所以它通常不是一个可行的解决方案。

Windows non-unicode API 中的文件路径要么在当前 ANSI(Microsoft 编解码器)代码页中解析,要么在 OEM 代码页中解析(另请参阅 https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfope). ANSI 是默认值。

所以您的问题转化为:如何将 UTF-8 或 UTF-16 字符串转换为 ANSI 或 OEM?

有一个 ANSI 转换的答案:How to convert from UTF-8 to ANSI using standard c++

无论如何,重要的是要认识到并非所有 UTF 字符串都可以用这些更窄的编解码器来表示...