c++ - 在 C++ Windows 中打开 utf8 编码的文件名

标签 c++ windows

考虑以下代码:

#include <iostream>
#include <boost\locale.hpp>
#include <Windows.h>
#include <fstream>

std::string ToUtf8(std::wstring str)
{
    std::string ret;
    int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0, NULL, NULL);
    if (len > 0)
    {
        ret.resize(len);
        WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), &ret[0], len, NULL, NULL);
    }
    return ret;
}

int main()
{
    std::wstring wfilename = L"D://Private//Test//एउटा फोल्दर//भित्रको फाईल.txt";
    std::string utf8path = ToUtf8(wfilename );
    std::ifstream iFileStream(utf8path , std::ifstream::in | std::ifstream::binary);
    if(iFileStream.is_open())
    {
        std::cout << "Opened the File\n";
        //Do the work here.
    }
    else
    {
        std::cout << "Cannot Opened the file\n";

    }
    return 0;

}

如果我正在运行该文件,我将无法打开该文件,从而进入 else block 。即使使用 boost::locale::conv::from_utf(utf8path ,"utf_8") 而不是 utf8path 也不起作用。如果我考虑使用 wifstream 并使用 wfilename 作为其参数,但我不想使用 wifstream,则该代码有效。有什么方法可以打开名称为 utf8 编码的文件吗?我正在使用 Visual Studio 2010

最佳答案

在 Windows 上,您必须使用 8 位 ANSI(并且它必须匹配用户的区域设置)或 UTF-16 作为文件名,没有其他选项可用。您可以在主代码中继续使用 string 和 UTF-8,但在打开文件时必须将 UTF-8 文件名转换为 UTF-16。效率较低,但这是您需要做的。

幸运的是,std::ifstreamstd::ofstream 的 VC++ 实现具有构造函数和 非标准 重载open() 方法接受 UTF-16 文件名的 wchar_t* 字符串。

explicit basic_ifstream(
    const wchar_t *_Filename,
    ios_base::openmode _Mode = ios_base::in,
    int _Prot = (int)ios_base::_Openprot
);

void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode = ios_base::in,
    int _Prot = (int)ios_base::_Openprot
);
void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode
);
explicit basic_ofstream(
    const wchar_t *_Filename,
    ios_base::openmode _Mode = ios_base::out,
    int _Prot = (int)ios_base::_Openprot
);

void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode = ios_base::out,
    int _Prot = (int)ios_base::_Openprot
);
void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode
);

您将不得不使用 #ifdef 来检测 Windows 编译(不幸的是,不同的 C++ 编译器识别不同)并在打开文件时临时将您的 UTF-8 字符串转换为 UTF-16。

#ifdef _MSC_VER
std::wstring ToUtf16(std::string str)
{
    std::wstring ret;
    int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
    if (len > 0)
    {
        ret.resize(len);
        MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &ret[0], len);
    }
    return ret;
}
#endif

int main()
{
    std::string utf8path = ...;
    std::ifstream iFileStream(
        #ifdef _MSC_VER
        ToUtf16(utf8path).c_str()
        #else
        utf8path.c_str()
        #endif
        , std::ifstream::in | std::ifstream::binary);
    ...
    return 0;
}

请注意,这只能保证在 VC++ 中工作。不保证其他适用于 Windows 的 C++ 编译器提供类似的扩展。

更新:从 Windows 10 Insider Preview Build 17035 开始,Microsoft 现在支持 UTF-8 作为系统范围的编码,用户可以将其语言环境设置为。从 Windows 10 版本 1903(内部版本 18362)开始,应用程序现在可以通过其应用程序 list 选择使用 UTF-8 作为进程范围的代码页,即使用户区域设置未设置为 UTF-8。这些功能允许使用基于 ANSI 的 API(如 CreateFileA()std::ifstream/std::ofstream 在内部使用) UTF-8 字符串。因此,理论上,启用此功能后,您可能能够将 UTF-8 编码的字符串传递给 std::ifstream/std::ofstream 并且它会“正常工作”。我无法确认,因为这在很大程度上取决于实现。坚持传递 UTF-16 文件名会更安全,因为这是 Windows 的 native 编码,ANSI API 将在内部简单地转换成它。

关于c++ - 在 C++ Windows 中打开 utf8 编码的文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30829364/

相关文章:

c++ - Windows 的 Bignum 库?

c++ - 检查 >> 提取的下一个值是字符串还是整数

c++ - 如何同时旋转和平移我的 Sprite ? cocos2dx 3.2

windows - 获取磁盘设备的物理设备对象名称

c++ - 如何使用 C++ 获取 system32 目录的完整路径?

node.js - 如何使用无服务器模块在本地调试 AWS Lambda Node.js?

c++ - 任何用于测试扩展 C/C++ #define 宏的实用程序?

c++ - Qt - QUdpSocket 绑定(bind)不断失败

c++ - 新建/删除 "override"与 "overload"

c# - 返回用户所属的所有 Active Directory 应用程序组的列表