2015-06-14 11 views
6

Rozważmy następujący kod:Otwarte utf8 zakodowane nazwy pliku w C++ Okna

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

} 

Jeżeli używam pliku, nie można otworzyć w ten sposób plik wejściem do bloku else. Nawet używanie boost::locale::conv::from_utf(utf8path ,"utf_8") zamiast utf8path nie działa. Kod działa, jeśli rozważam użycie parametru wifstream i użycie parametru wfilename jako jego parametru, ale nie chcę używać wifstream. Czy istnieje sposób, aby otworzyć plik o nazwie kodowanej utf8? Używam Visual Studio 2010.

+1

Żadne z bazowych interfejsów API systemu Windows nie używają UTF8. std :: ifstream w końcu wywoła CreateFileA lub CreateFileW, aby otworzyć plik, po czym te funkcje przyjmują UTF8. –

+0

Więc jeśli mam zamiar użyć 'ifstream', jak powinienem zmienić kod aby działał. Powinienem używać 'wstring'a – Pant

+0

Chodzi o to, że próbuję zrobić kod na platformie. Ponieważ Linux jest już świadomym unicode, kod powinien prawdopodobnie działać, jeśli użyję 'ifstream'. Jak mam sobie z tym poradzić? – Pant

Odpowiedz

11

W systemie Windows MUST użycie 8bit ANSI (i to musi dopasować ustawienia regionalne użytkownika) lub UTF16 dla nazw plików, nie ma innych dostępnych opcji. Możesz nadal używać string i UTF8 w swoim głównym kodzie, ale będziesz musiał konwertować nazwy plików UTF8 do UTF16 podczas otwierania plików. Mniej wydajne, ale to jest to, co musisz zrobić.

szczęście realizacja VC++ 's std::ifstream i std::ofstream mieć niestandardowych przeciążeń swoich konstruktorów i open() metod akceptują wchar_t* ciągi dla nazw 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 
); 

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

Będziesz musiał użyć #ifdef wykryć kompilację Windows (niestety, różne kompilatory C++, które w różny sposób zidentyfikować) i tymczasowo zamienić ciąg znaków UTF-8 do UTF16 podczas otwierania pliku.

#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 uft8path = ...; 
    std::ifstream iFileStream(
     #ifdef _MSC_VER 
     ToUtf16(uft8path).c_str() 
     #else 
     uft8path.c_str() 
     #endif 
     , std::ifstream::in | std::ifstream::binary); 
    ... 
    return 0; 
} 

Należy pamiętać, że działa to wyłącznie w wersji VC++. Inne kompilatory C++ dla systemu Windows nie gwarantują podobnych rozszerzeń.

+0

+1 to działało. Dla tych, którzy chcą przekonwertować 'utf8' na' utf16', istnieje również inna funkcja, która jest dostępna [tutaj] (http://stackoverflow.com/a/7154226/2634612). – Pant

+2

Istnieje wiele implementacji konwersji UTF. Implementacje ręczne (takie jak te, z którymi się łączyłeś), biblioteki Unicode, takie jak libiconv i ICU, a nawet 'std :: codecvt_utf8_utf16' w C++ 11. –

+0

Zamiast umieszczać '# ifdef' wewnątrz każdego pliku, możesz utworzyć funkcję' filename (const std :: string & fname) 'i umieścić wszystkie te paskudztwa w jednym miejscu. Następnie wystarczy użyć tej funkcji w nazwie pliku, gdziekolwiek trzeba otworzyć plik. –