2015-06-14 17 views
6

Xét đoạn mã sau:mở utf8 mã hóa tên tập tin trong C++ của 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; 

} 

Nếu tôi chạy các tập tin, tôi không thể mở các tập tin do đó bước vào khối else. Ngay cả khi sử dụng boost::locale::conv::from_utf(utf8path ,"utf_8") thay vì utf8path không hoạt động. Mã hoạt động nếu tôi xem xét sử dụng wifstream và sử dụng wfilename làm thông số của nó, nhưng tôi không muốn sử dụng wifstream. Có cách nào để mở tệp có tên là utf8 được mã hóa không? Tôi đang sử dụng Visual Studio 2010.

+1

Không có API Windows nào bên dưới sử dụng UTF8. std :: ifstream cuối cùng sẽ gọi CreateFileA hoặc CreateFileW để mở tệp, các chức năng này mất UTF8. –

+0

Vì vậy, nếu tôi sẽ sử dụng 'ifstream' làm thế nào tôi nên thay đổi mã để làm cho nó hoạt động. Tôi có nên sử dụng 'wstring' – Pant

+0

Điều này là tôi đang cố gắng làm cho nền tảng mã chéo. Vì Linux đã được unicode nhận thức, mã có lẽ nên làm việc nếu tôi sử dụng 'ifstream'. Tôi nên giải quyết tình huống này như thế nào? – Pant

Trả lời

11

Trên Windows, bạn PHẢI sử dụng 8bit ANSI (và nó phải phù hợp với địa phương của người dùng) hoặc UTF16 cho tên tập tin, không có tùy chọn khác có sẵn. Bạn có thể tiếp tục sử dụng string và UTF8 trong mã chính của mình, nhưng bạn sẽ phải chuyển đổi tên tệp UTF8 thành UTF16 khi bạn mở tệp. Ít hiệu quả hơn, nhưng đó là những gì bạn cần làm.

May mắn thay, thi hành std::ifstreamstd::ofstream VC++ 's có quá tải phi tiêu chuẩn của nhà thầu của họ và open() phương pháp để chấp nhận wchar_t* chuỗi cho tên tập tin 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ạn sẽ phải sử dụng một #ifdef để dò tìm Windows biên soạn (không may, trình biên dịch C++ khác nhau xác định rằng cách khác nhau) và tạm thời chuyển đổi chuỗi UTF8 của bạn để UTF16 khi mở một tập tin.

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

Lưu ý rằng điều này chỉ được đảm bảo hoạt động trong VC++. Các trình biên dịch C++ khác cho Windows không được bảo đảm để cung cấp các phần mở rộng tương tự.

+0

+1 tính năng này hoạt động. Đối với những người muốn chuyển đổi 'utf8' thành' utf16', cũng có một hàm khác có sẵn [ở đây] (http://stackoverflow.com/a/7154226/2634612). – Pant

+2

Có nhiều triển khai chuyển đổi UTF có sẵn. Triển khai thủ công (giống như bạn đã liên kết đến), các thư viện Unicode như libiconv và ICU, và thậm chí cả 'std :: codecvt_utf8_utf16' trong C++ 11. –

+0

Thay vì đặt '# ifdef' bên trong mỗi tệp đang mở, bạn có thể tạo một hàm' tên tệp (const std :: string & fname) 'và đặt tất cả các thứ yucky vào một nơi. Sau đó, bạn chỉ cần sử dụng chức năng đó trên tên tập tin bất cứ nơi nào bạn cần để mở một tập tin. –

Các vấn đề liên quan