C++ Windowsでutf8エンコードされたファイル名を開く 質問する

C++ Windowsでutf8エンコードされたファイル名を開く 質問する

次のコードを考えてみましょう。

#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;

}

ファイルを実行している場合、ファイルを開くことができないため、ブロックに入りますelseboost::locale::conv::from_utf(utf8path ,"utf_8")の代わりにを使用しても機能しません。 を使用し、 をパラメータとして使用することutf8pathを検討すればコードは機能しますが、 は使用したくありません。名前をエンコードしてファイルを開く方法はありますか? を使用しています。wifstreamwfilenamewifstreamutf8Visual Studio 2010

ベストアンサー1

Windowsでは、しなければならない8ビットANSIを使用します(そしてそれはしなければならないファイル名に .utf-8 (ユーザーのロケールに一致) または UTF-16 を使用する場合、他のオプションはありません。stringメイン コードでは UTF-8 を使い続けることができますが、ファイルを開くときに UTF-8 ファイル名を UTF-16 に変換する必要があります。効率は悪くなりますが、必要なことです。

幸いなことに、VC++の実装std::ifstreamstd::ofstream非標準UTF-16 ファイル名の文字列open()を受け入れるために、コンストラクタとメソッドをオーバーロードします。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
);

Windows コンパイルを検出するには (残念ながら、C++ コンパイラによってその識別方法が異なります)を使用し、ファイルを開くときに UTF-8 文字列を一時的に UTF-16 に変換する必要があります#ifdef

#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) 以降、アプリケーションは、ユーザー ロケールが UTF-8 に設定されていない場合でも、アプリ マニフェストを介してプロセス全体のコードページとして UTF-8 を使用するように選択できるようになりました。これらの機能により、ANSI ベースの API (内部で/が使用するCreateFileA()など) が UTF-8 文字列を処理できるようになります。つまり、std::ifstreamstd::ofstream理論的にはこの機能をオンにすると、かもしれないstd::ifstreamUTF-8 でエンコードされた文字列を/に渡すことができstd::ofstream、それが「問題なく動作する」という保証はありません。これは実装に大きく依存するため、確認できません。UTF-16 ファイル名を渡す方が安全です。これは Windows のネイティブ エンコードであり、ANSI API は単純に内部で UTF-16 に変換します。

おすすめ記事