2015-06-14 8 views
6

Si consideri il seguente codice:Aprire utf8 codificato il nome del file in C++ di 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; 

} 

Se si esegue il file, non posso aprire il file entrando così nel blocco else. Anche l'utilizzo di boost::locale::conv::from_utf(utf8path ,"utf_8") invece di utf8path non funziona. Il codice funziona se considero l'utilizzo di wifstream e l'utilizzo di wfilename come parametro, ma non desidero utilizzare wifstream. C'è un modo per aprire il file con il suo nome codificato utf8? Sto usando Visual Studio 2010.

+1

Nessuna delle API di Windows sottostanti utilizza UTF8. std :: ifstream alla fine chiamerà CreateFileA o CreateFileW per aprire il file, il nether di queste funzioni prende UTF8. –

+0

Quindi, se ho intenzione di usare 'ifstream', come dovrei cambiare il codice per farlo funzionare. Dovrei usare 'wstring' – Pant

+0

Il fatto è che sto cercando di rendere il codice multipiattaforma. Dato che Linux è già sensibile all'unicode, il codice dovrebbe funzionare se uso 'ifstream'. Come dovrei affrontare questa situazione? – Pant

risposta

11

Su Windows, è MUST uso 8bit ANSI (e deve corrispondere locale dell'utente) o UTF16 per i nomi dei file, non c'è altra opzione disponibile. Puoi continuare a utilizzare string e UTF8 nel tuo codice principale, ma dovrai convertire i nomi dei file UTF8 in UTF16 quando stai aprendo i file. Meno efficiente, ma è quello che devi fare.

Fortunatamente, l'implementazione di VC++ s 'di std::ifstream e std::ofstream hanno non standard sovraccarichi dei loro costruttori e open() metodi per accettare wchar_t* stringhe per i nomi dei file 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 
); 

Si dovrà utilizzare un #ifdef per rilevare la compilazione di Windows (purtroppo, diversi compilatori C++ identificare che in modo diverso) temporaneamente convertire la stringa UTF8 per UTF16 quando si apre un file.

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

Si noti che questo è garantito per funzionare solo in VC++. Non è garantito che altri compilatori C++ per Windows forniscano estensioni simili.

+0

+1 ha funzionato. Per coloro che vogliono convertire 'utf8' in' utf16', esiste un'altra funzione disponibile [qui] (http://stackoverflow.com/a/7154226/2634612). – Pant

+2

Sono disponibili molte implementazioni di conversione UTF. Implementazioni manuali (come quella a cui ti sei collegato), librerie Unicode come libiconv e ICU e persino 'std :: codecvt_utf8_utf16' in C++ 11. –

+0

Invece di mettere '# ifdef' dentro ogni file aperto, puoi creare una funzione' filename (const std :: string & fname) 'e mettere tutte le cose schifose in un posto. Quindi usi questa funzione sul nome del file ovunque sia necessario per aprire un file. –

Problemi correlati