2011-01-23 19 views
25

¿Cómo puedo leer un archivo Unicode (UTF-8) en wstring (s) en la plataforma de Windows?Lea el archivo Unicode UTF-8 en wstring

+0

Por "Unicode" Qué quiere decir UTF-8 o UTF-16? ¿Y qué plataforma estás usando? – dan04

+0

utf-8 en Windows – Abdelwahed

+2

Lea este artículo: [Lectura de UTF-8 con flujos de C++] (http: //www.codeproject.com/KB/stl/utf8facet.aspx) – Nawaz

Respuesta

0

Respondió esta pregunta en Confused about C++'s std::wstring, UTF-16, UTF-8 and displaying strings in a windows GUI. En resumen, wstring se basa en el estándar UCS-2, que es el predecesor de UTF-16. Este es un estándar estrictamente de dos bytes. Creo que esto cubre el árabe.

+1

Creo que puede usar wstring con UTF-16 –

+0

@Daivd: En realidad, usted es incorrecto, y esto es un malentendido común. UTF-16 cubre 1,112,064 puntos de código de 0 a 0x10FFFF. El esquema requiere un almacenamiento de longitud variable de una o dos palabras de 16 bits, mientras que UCS-2 era estrictamente una palabra de 16 bits. Si rastrea la definición de wchar_t, encontrará que tiene como su raíz es un tipo primitivo de 16 bits (generalmente un corto). – ThomasMcLeod

+1

@David: Técnicamente, un 'wstring' es solo una matriz de enteros de 16 bits en Windows. Puede almacenar datos UCS-2 o UTF-16 o lo que quiera en él. La mayoría de las API de Windows aceptan cadenas UTF-16 hoy en día. – Philipp

4

Aquí es una función específica de la plataforma para Windows solamente:

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

uso de este modo:

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

Nota todo el archivo se carga en la memoria, por lo que puede que no desee utilizarlo para archivos muy grandes

+3

También podría funcionar todo el camino: _wfopen (filename.c_str(), L "rt, ccs = UTF-8"); La conversión ahora es automática. –

+0

Gracias, respuesta editada. – AshleysBrain

+0

En realidad, lo recuperó, los documentos de _wfopen dicen que se convierte en caracteres anchos automáticamente, y este código no lo tiene en cuenta. – AshleysBrain

12

De acuerdo con un comentario de @Hans Passant, la forma más sencilla es usar _wfopen_s. Abra el archivo con el modo rt, ccs=UTF-8.

Aquí hay otra solución pura de C++ que funciona al menos con 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"); 
} 

excepción de locale::empty() (aquí locale::global() podría funcionar también) y la sobrecarga de wchar_t* del basic_ifstream constructor, esto aún debe ser bastante estándar-obediente (donde "estándar" significa C++ 0x, por supuesto).

+5

¿Por qué no 'borrar convertidor'? – Mikhail

+1

"Overload 7 se suele llamar con su segundo argumento, f, obtenido directamente de una nueva expresión: la configuración regional es responsable de llamar a la eliminación correspondiente de su propio destructor". [link] (http://en.cppreference.com/w/cpp/locale/locale/locale) – sven

+0

Esto solo lee la primera línea del archivo ... –

20

Con el apoyo de C++ 11, puede utilizar std::codecvt_utf8 facetque encapsula la conversión entre una cadena de codificación UTF-8 bytes y UCS2 o UCS4 cadena de caracteres y que se puede utilizar para leer y escribir archivos UTF-8, tanto texto y binario

Para utilizar facet por lo general crea locale objectque encapsula la información específica de la cultura como un conjunto de facetas que definen colectivamente un entorno localizado específica. Una vez que tenga un objeto local, puede imbue su búfer de la secuencia con ella:

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

que puede ser utilizado como esto:

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

alternativa, puede configurar the global C++ locale antes de trabajar con corrientes de cuerda, que hace que todas las llamadas futuras al constructor predeterminado std::locale devuelvan una copia de la configuración regional global de C++ (no es necesario imbuir de manera explícita las memorias intermedias de la secuencia):

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

¿Eso 'nuevo codecvt_utf8' requiere un' delete' correspondiente? –

+0

Sin necesidad de eliminar explícitamente codecvt_utf8. Esto se hace en el destructor de std :: locale cuando el refcounter de codecvt_utf8 se convierte en cero (ver http://en.cppreference.com/w/cpp/locale/locale/%7Elocale) – MrTux

-3

Esto es un poco crudo, pero ¿qué hay de leer el archivo como viejos bytes sin formato y luego convertir el búfer de bytes a wchar_t *?

Algo así como:

#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

Hola. Gracias por compartir. Apreciado. ¿Puedes agregar un poco más de contexto? Por qué esta respuesta a una pregunta de 6 años. Gracias. – wp78de

+0

Tengo algunas preguntas recientemente, pero las he solucionado ahora, quiero compartir mi solución para ayudar a otros. –

+0

Eso es bueno. ¿Pero cómo es tu respuesta diferente de la respuesta de @ LihO? Solo usas una configuración regional diferente, ¿verdad? – wp78de