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

Pan*_*ant 11 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;

}
Run Code Online (Sandbox Code Playgroud)

如果我正在运行该文件,我无法打开文件,因此进入该else块.即使使用boost::locale::conv::from_utf(utf8path ,"utf_8")utf8path不是工作.如果我考虑使用wifstream和使用wfilename它作为参数,代码可以工作,但我不想使用wifstream.有没有办法打开文件名称utf8编码?我在用Visual Studio 2010.

Rem*_*eau 22

在Windows上,你必须使用8位ANSI(它必须匹配用户的语言环境)或UTF16用于文件名,没有其他选项可用.您可以string在主代码中继续使用UTF8,但在打开文件时必须将UTF8文件名转换为UTF16.效率较低,但这就是你需要做的.

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

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
);
Run Code Online (Sandbox Code Playgroud)

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
);
Run Code Online (Sandbox Code Playgroud)

您将不得不使用一个#ifdef来检测Windows编译(不幸的是,不同的C++编译器识别不同)并在打开文件时暂时将UTF8字符串转换为UTF16.

#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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这只能保证在VC++中有效.其他用于Windows的C++编译器无法保证提供类似的扩展.

  • 有许多UTF转换实现可用.手动实现(如您链接到的那个),像libiconv和ICU这样的Unicode库,甚至是C++ 11中的`std :: codecvt_utf8_utf16`. (2认同)
  • @Raedwald不,我的意思是8位ANSI。未以UTF编码的Unicode字符串需要8位编码,例如Windows-1252等(7位ASCII是UTF-8的子集)。在Windows上,使用实现这些编码的[代码页](https://msdn.microsoft.com/zh-cn/library/windows/desktop/dd317752.aspx)来实现用户区域设置。因此,Windows系统上的文件名必须使用UTF-16或用户的默认ANSI代码页进行编码。 (2认同)