Как я могу прочитать файл Unicode (UTF-8) в wstring
на платформе Windows?
Чтение файла UIF-8 Unicode в wstring
Ответ 1
С поддержкой С++ 11 вы можете использовать std:: codecvt_utf8 facet, который инкапсулирует преобразование между кодированной байтовой строкой UTF-8 и символьной строкой UCS2 или UCS4 и который может использоваться для чтения и записи файлов UTF-8, как текстовых, так и двоичных.
Чтобы использовать facet, вы обычно создаете объект локали, который инкапсулирует информацию, относящуюся к культуре, как набор граней, которые в совокупности определяют конкретную локализованную среду. После того, как у вас есть локальный объект, вы можете imbue создать свой буфер потока:
#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();
}
который можно использовать следующим образом:
std::wstring wstr = readFile("a.txt");
В качестве альтернативы вы можете установить глобальную локаль С++, прежде чем работать со строковыми потоками, что приводит ко всем будущим вызовам конструктора по умолчанию std::locale
, чтобы вернуть копию глобального С++ locale (вам не нужно явно вводить в него потоковые буферы):
std::locale::global(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
Ответ 2
Согласно комментарию @Hans Passant, самый простой способ - использовать _wfopen_s. Откройте файл с режимом rt, ccs=UTF-8
.
Вот еще одно чистое решение на С++, которое работает как минимум с VС++ 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");
}
За исключением locale::empty()
(здесь может работать и locale::global()
) и перегрузки wchar_t*
конструктора basic_ifstream
, это должно быть даже довольно стандартно (где "standard" означает С++ 0x, конечно).
Ответ 3
Здесь определенная для платформы функция только для Windows:
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;
}
Используйте так:
std::wstring mytext = LoadUtf8FileToString(L"C:\\MyUtf8File.txt");
Обратите внимание, что весь файл загружен в память, поэтому вы можете не использовать его для очень больших файлов.
Ответ 4
Этот вопрос был рассмотрен в Confused о std:: wstring, UTF-16, UTF-8 в С++ и отображении строк в графическом интерфейсе Windows. В целом, wstring основывается на стандарте UCS-2, который является предшественником UTF-16. Это строго двухбайтовый стандарт. Я считаю, что это охватывает арабский язык.
Ответ 5
#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();
}
Ответ 6
Это немного грубо, но как насчет чтения файла в виде простых старых байтов, а затем байт-буфер на wchar_t *?
Что-то вроде:
#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;
}