2011-01-23 32 views
25

Làm cách nào để đọc tệp Unicode (UTF-8) thành wstring (s) trên nền tảng Windows?Đọc tệp Unicode UTF-8 thành wstring

+0

By "Unicode" Ý anh là UTF-8 hoặc UTF-16? Và bạn đang sử dụng nền tảng nào? – dan04

+0

utf-8 trên windows – Abdelwahed

+2

Đọc bài viết này: [Đọc UTF-8 với luồng C++] (http: //www.codeproject.com/KB/stl/utf8facet.aspx) – Nawaz

Trả lời

0

Câu hỏi này được giải quyết trong Confused about C++'s std::wstring, UTF-16, UTF-8 and displaying strings in a windows GUI. Tóm lại, wstring dựa trên tiêu chuẩn UCS-2, là tiền thân của UTF-16. Đây là một tiêu chuẩn hai byte nghiêm ngặt. Tôi tin điều này bao gồm tiếng Ả Rập.

+1

Tôi nghĩ rằng bạn có thể sử dụng wstring với UTF-16 –

+0

@Daivd: Trên thực tế bạn không chính xác, và đây là một sự hiểu lầm phổ biến. UTF-16 bao gồm 1.112.064 điểm mã từ 0 đến 0x10FFFF. Đề án này yêu cầu lưu trữ độ dài thay đổi của một hoặc hai từ 16 bit, trong khi UCS-2 hoàn toàn là một từ 16 bit. Nếu bạn theo dõi lại định nghĩa wchar_t, bạn sẽ thấy rằng nó có như là root của nó một loại nguyên thủy của 16-bit (thường là một đoạn ngắn). – ThomasMcLeod

+1

@David: Về mặt kỹ thuật, một chuỗi «wstring' chỉ là một mảng các số nguyên 16 bit trên Windows. Bạn có thể lưu trữ dữ liệu UCS-2 hoặc UTF-16 hoặc bất kỳ thứ gì bạn thích trong đó. Hầu hết các API Windows đều chấp nhận chuỗi UTF-16 ngày nay. – Philipp

4

Dưới đây là một chức năng nền tảng cụ thể cho Windows chỉ:

size_t GetSizeOfFile(const std::wstring& path) 
{ 
    struct _stat fileinfo; 
    _wstat(path.c_str(), &fileinfo); 
    return fileinfo.st_size; 
} 

std::wstring LoadUtf8FileToString(const std::wstring& filename) 
{ 
    std::wstring buffer;   // stores file contents 
    FILE* f = _wfopen(filename.c_str(), L"rtS, ccs=UTF-8"); 

    // Failed to open file 
    if (f == NULL) 
    { 
     // ...handle some error... 
     return buffer; 
    } 

    size_t filesize = GetSizeOfFile(filename); 

    // Read entire file contents in to memory 
    if (filesize > 0) 
    { 
     buffer.resize(filesize); 
     size_t wchars_read = fread(&(buffer.front()), sizeof(wchar_t), filesize, f); 
     buffer.resize(wchars_read); 
     buffer.shrink_to_fit(); 
    } 

    fclose(f); 

    return buffer; 
} 

Sử dụng như sau:

std::wstring mytext = LoadUtf8FileToString(L"C:\\MyUtf8File.txt"); 

Lưu ý toàn bộ tập tin được nạp vào bộ nhớ, vì vậy bạn có thể không muốn sử dụng nó cho các tệp rất lớn.

+3

Cũng có thể đi toàn bộ con đường: _wfopen (filename.c_str(), L "rt, ccs = UTF-8"); Chuyển đổi giờ đây tự động. –

+0

Cảm ơn, câu trả lời đã chỉnh sửa. – AshleysBrain

+0

Trên thực tế, cuộn lại, tài liệu trên _wfopen cho biết nó tự động chuyển thành ký tự rộng và mã này không tính đến tài khoản đó. – AshleysBrain

12

Theo nhận xét của @Hans Passant, cách đơn giản nhất là sử dụng _wfopen_s. Mở tệp với chế độ rt, ccs=UTF-8.

Dưới đây là một tinh khiết C++ giải pháp mà làm việc ít nhất là với VC++ 2010:

#include <locale> 
#include <codecvt> 
#include <string> 
#include <fstream> 
#include <cstdlib> 

int main() { 
    const std::locale empty_locale = std::locale::empty(); 
    typedef std::codecvt_utf8<wchar_t> converter_type; 
    const converter_type* converter = new converter_type; 
    const std::locale utf8_locale = std::locale(empty_locale, converter); 
    std::wifstream stream(L"test.txt"); 
    stream.imbue(utf8_locale); 
    std::wstring line; 
    std::getline(stream, line); 
    std::system("pause"); 
} 

Trừ locale::empty() (ở đây locale::global() có thể làm việc tốt) và wchar_t* tình trạng quá tải của các nhà xây dựng basic_ifstream, điều này thậm chí nên được khá tuân thủ tiêu chuẩn (trong đó "tiêu chuẩn" có nghĩa là C++ 0x, tất nhiên).

+5

Tại sao bạn không 'xóa converter'? – Mikhail

+1

"Quá tải 7 thường được gọi với đối số thứ hai của nó, f, thu được trực tiếp từ một biểu thức mới: miền địa phương chịu trách nhiệm gọi việc xóa trùng khớp khỏi hủy của riêng nó." [link] (http://en.cppreference.com/w/cpp/locale/locale/locale) – sven

+0

Điều này chỉ đọc dòng đầu tiên của tập tin .. –

20

Với C++ 11 hỗ trợ, bạn có thể sử dụng std::codecvt_utf8 facetmà đóng gói chuyển đổi giữa một chuỗi UTF-8 mã hóa byte và UCS2 hoặc UCS4 chuỗi ký tựmà có thể được sử dụng để đọc và ghi file UTF-8, cả hai văn bản và nhị phân.

Để sử dụng facet bạn thường tạo locale objectđó bao gồm thông tin văn hóa cụ thể như là một tập các phương diện nhằm xác định chung một môi trường cục bộ cụ thể. Một khi bạn có một đối tượng tên địa phương, bạn có thể imbue đệm luồng của mình với nó:

#include <sstream> 
#include <fstream> 
#include <codecvt> 

std::wstring readFile(const char* filename) 
{ 
    std::wifstream wif(filename); 
    wif.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>)); 
    std::wstringstream wss; 
    wss << wif.rdbuf(); 
    return wss.str(); 
} 

mà có thể được sử dụng như thế này:

std::wstring wstr = readFile("a.txt"); 

Hoặc bạn có thể thiết lập the global C++ locale trước khi bạn làm việc với những con suối chuỗi đó khiến tất cả các cuộc gọi trong tương lai tới hàm khởi tạo mặc định std::locale để trả lại bản sao của ngôn ngữ C++ toàn cầu (bạn không cần phải lọc rõ ràng bộ đệm luồng với nó):

std::locale::global(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>)); 
+1

Liệu 'codecvt_utf8' mới có yêu cầu 'xóa' tương ứng không? –

+0

Không có neet để xóa codecvt_utf8 một cách rõ ràng. Điều này được thực hiện trong destructor của std :: locale khi refcounter của codecvt_utf8 trở thành số không (xem http://en.cppreference.com/w/cpp/locale/locale/%7Elocale) – MrTux

-3

Đây là một chút thô, nhưng làm thế nào về việc đọc tệp dưới dạng byte cũ đơn giản sau đó đúc bộ đệm byte thành wchar_t *?

Cái gì như:

#include <iostream> 
#include <fstream> 
std::wstring ReadFileIntoWstring(const std::wstring& filepath) 
{ 
    std::wstring wstr; 
    std::ifstream file (filepath.c_str(), std::ios::in|std::ios::binary|std::ios::ate); 
    size_t size = (size_t)file.tellg(); 
    file.seekg (0, std::ios::beg); 
    char* buffer = new char [size]; 
    file.read (buffer, size); 
    wstr = (wchar_t*)buffer; 
    file.close(); 
    delete[] buffer; 
    return wstr; 
} 
1
#include <iostream> 
#include <fstream> 
#include <string> 
#include <locale> 
#include <cstdlib> 

int main() 
{ 
    std::wifstream wif("filename.txt"); 
    wif.imbue(std::locale("zh_CN.UTF-8")); 

    std::wcout.imbue(std::locale("zh_CN.UTF-8")); 
    std::wcout << wif.rdbuf(); 
} 
+0

Xin chào. Cám ơn vì đã chia sẻ. Đánh giá cao. Bạn có thể thêm ngữ cảnh nhiều hơn một chút không? Tại sao câu trả lời này cho một câu hỏi 6 tuổi. Cảm ơn. – wp78de

+0

Tôi có một số câu hỏi gần đây, nhưng tôi đã giải quyết ngay bây giờ, tôi muốn chia sẻ giải pháp của mình để giúp đỡ người khác. –

+0

Thật tuyệt. Nhưng câu trả lời của bạn khác với câu trả lời của @ LihO như thế nào? Bạn chỉ cần sử dụng một miền địa phương khác, phải không? – wp78de

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