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

InformationsquelleAutor Abdelwahed | 2011-01-23

6 Comentarios

  1. 32

    Con C++11, puede utilizar std::codecvt_utf8 faceta que encapsula la conversión entre una codificación UTF-8, cadena de bytes y UCS2 o UCS4 cadena de caracteres y que puede ser utilizado para leer y escribir archivos UTF-8, ambos de texto y binarios.

    Con el fin de utilizar faceta generalmente se crea configuración regional del objeto que encapsula la cultura específica de la información como un conjunto de facetas que, en conjunto, definen un determinado localizada medio ambiente. Una vez que usted tiene una configuración regional del objeto, puede imbuir su stream buffer 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 esta:

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

    Alternativamente, usted puede establecer el global de C++ configuración regional antes de trabajar con la cadena de arroyos que hace que todas las futuras convocatorias para la std::locale constructor predeterminado para devolver una copia de la global de C++ regional (no es necesario explícitamente imbuir búferes de secuencia con ella luego):

    std::locale::global(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
    • ¿Que new codecvt_utf8 requieren de la correspondiente delete?
    • No limpio para 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 en.cppreference.com/w/cpp/locale/locale/%7Elocale)
    • Para aquellos que utilizan esta respuesta, std::locale::empty() tiene un problema en clang: error: ningún miembro llamado ‘vacío’ en ‘std::__1::locale’.
  2. 14

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

    Aquí es otro puro de C++ solución 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");
    }

    Excepto para locale::empty() (aquí locale::global() podría funcionar tan bien) y el wchar_t* sobrecarga de la basic_ifstream constructor, esto debe ser bastante estándar-compatible (donde «estándar» significa que C++0x, por supuesto).

    • ¿Por qué no delete converter?
    • «La sobrecarga de 7 que se suele llamar con su segundo argumento, f, obtenida directamente a partir de una nueva expresión: la configuración regional es responsable de llamar a la coincidencia de borrar de su propio destructor.» enlace
    • Esto sólo lee la primera línea del archivo..
    • Esto funciona bien. Curioso, como yo no puede encontrar una gran cantidad de información sobre ella, y a mí me funciona muy bien sin él, ¿cuál es la corriente.imbuir a hacer exactamente? Parece como si lo es el establecimiento de algún tipo de defecto tipo, pero es esto necesario? También, para la primera línea de comentario, poner su getline en un tiempo(getline(corriente, línea)) bucle para ver más de la primera línea.
  3. 6

    Aquí está una plataforma específica de la función solo para 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;
    }

    Uso así:

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

    Nota todo el archivo es cargado en memoria, por lo que es posible que no desee utilizar para archivos muy grandes.

    • Así se podría ir todo el camino: _wfopen(nombre de archivo.c_str(), L»rt, ccs=UTF-8″); la Conversión es ahora automática.
    • Gracias, editado respuesta.
    • En realidad, la hizo rodar de nuevo, documentos en el _wfopen decir que se convierte en caracteres anchos automáticamente, y este código no tomar eso en cuenta.
    • El nombre de archivo. Cita: Simply using _wfopen has no effect on the coded character set used in the file stream.
    • Estás seguro? La forma en que los tomé de la documentación, especificando t en el modo de ccs=UTF-8 causas de caracteres para convertir como son la lectura y de la secuencia.
    • Sí, la cita se refiere a la utilización de _wfopen sin el ccs= modo de especificador. Usted necesita _wfopen (según el manual _wfopen_s es preferible) y ccs=UTF-8.
    • A finales de editar en el mes de agosto: resulta @Hans Pasante de la manera que es mejor editado la respuesta a usar!
    • No imprimir un archivo con las letras griegas que escribí. Se detiene inmediatamente cuando se cumple el primer carácter griego. Lee el anterior en inglés, aunque. Otras soluciones solía leer los caracteres griegos en su mayoría como ? (no, no me refiero a la consola no los reconocen y los muestra como ?, realmente quiero decir que el sistema no reconoce el texto griego escrito en el archivo). No he sido capaz de hacer que funcione, que sólo se puede obtener el texto griego de std::cin y almacenar correctamente.

  4. 2
    #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();
    }
    • Hola. Gracias por compartir. Apreciado. Se puede añadir un poco más de contexto? Por qué esta respuesta a una de 6 años de edad de las preguntas. Gracias.
    • Tengo algunas pregunta hace poco, pero me han resuelto ahora, quiero compartir mi solución para ayudar a los demás.
    • Que agradable. Pero, ¿cómo es su respuesta diferente de @LihO la respuesta? Usted sólo tiene que utilizar una configuración regional diferente, ¿verdad?
  5. 0

    Este tema fue abordado en Confundido acerca de C++’s std::wstring, UTF-16, UTF-8 y la visualización de las cuerdas en la GUI de windows. En suma, wstring se basa en la UCS-2 estándar, que es la predecesora de UTF-16. Esto es estrictamente una de dos bytes estándar. Creo que esto cubre árabe.

    • Creo que se puede utilizar wstring con UTF-16
    • 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 una longitud variable de almacenamiento de una o dos palabras de 16 bits, mientras que UCS-2 fue estrictamente una palabra de 16 bits. Si el rastro de la definición de wchar_t, usted encontrará que es tiene como raíz una primative tipo de 16-bits (generalmente corto).
    • Técnicamente, un wstring es simplemente una matriz de enteros de 16 bits en Windows. Usted puede almacenar UCS-2 o UTF-16 datos o lo que quieras en ella. La mayoría de las Api de Windows no aceptar UTF-16 cadenas de hoy en día.
    • Pensé que todas las Api de Windows son UTF-16. Cuáles tomar UCS-2?
    • Me temo que el malentendido está en usted. Yo sé acerca de la variable longitud de UTF-16 y los pares suplentes. Pero que es perfectamente compatible con wstring. Un par suplente toma 2 wchar_t elementos.
    • usted puede almacenar un subconjunto de caracteres UTF-16 en un wstring. Por ejemplo, usted no puede almacenar los Balineses secuencia de comandos de caracteres en un wstring, pero no son válidos codificaciones de UTF-16 para estos personajes. en.wikipedia.org/wiki/Balinese_script
    • eso no es correcto. UTF-16 utiliza 16 bits unidades de código, es decir, un wchar_t en Windows.
    • Estoy de acuerdo con David. Usted puede almacenar cualquier punto de código Unicode en un wstring si te tratan como UTF-16 de la cadena. No BMP código de puntos se necesitan dos unidades de código, pero no hay nada de malo con eso.
    • ninguna de mis anteriores. Yo refiere a la Brāhmī script, el cual es todavía más oscuro
    • Creo (pero no estoy seguro, no estoy usando Windows ahora) que la consola todavía no manejar no-BMP caracteres. Es discutible si que tiene algo que ver con la propia API.
    • cualquier cosa con un punto de código Unicode puede ser representado en UTF-16
    • la consola es todo un mundo de dolor! Incluso conseguir que la pantalla no ANSI puntos de código es un ejercicio de masoquismo extremo!
    • No, se trata de dos líneas, consulte blogs.msdn.com/b/michkap/archive/2008/03/18/8306597.aspx
    • Muy interesante! Estoy acostumbrado a Python en Windows que tiene la basura de la consola de apoyo.
    • Parece que estamos discutiendo acerca de la semántica. Usted dijo: «creo que puede wstring con UTF-16.» Eso significa que más de la tienda. Esto significa tienda y lo han interpretado correctamente por lo menos stdio. He intentado mediante SMP personajes con wcout y un wstring en Windows 7 pro de 64 bits, y tengo un montón de tonterías.
    • Eso no significa que el problema es con wstring.
    • Creo que es una de Python problema, no es un problema de Windows. Sé el Python desarrolladores se esfuerzan para conseguir la compatibilidad con Unicode en todas partes, pero creo que es difícil llevar la real de Windows semántica de un modelo que asume que el sistema operativo corrientes son siempre bytes y codificación-agnóstico (que es cierto para el archivo de Unix y de la consola de arroyos y para Windows secuencias de archivo, pero no para la consola de Windows). No he estudiado el código fuente de Python, pero creo que al menos en algún momento en el pasado se asumía que este modelo de sostener.
    • Es sólo una verdadera vergüenza que la consola de Windows se siente un poco descuidado.
    • No creo que el MSVC++ iostreams biblioteca de cualquier tipo de Unicode, excepto que permite nombres de archivo Unicode. Todas las soluciones para el uso de Unicode en C++ son puro C soluciones, ya sea usando la API de Windows directamente o mediante extensiones no estándar para la biblioteca C.
    • Estoy de acuerdo. Por eso digo que wstring es UCS-2 y no UTF-16.
    • el problema no es con wstring de almacenamiento, es con la típica wstring uso y UTF-16. Puede almacenar UTF-16 en un bitset si quieres, pero es que al utilizarlo con UTF-16? De verdad que no.
    • ¿qué te gustaría usar en lugar de wstring?
    • El MSVC++ estándar de la biblioteca no admite UCS-2, bien. La última vez que revisé, el C++ locales no admite ninguna configuración regional Unicode, lo Unicode de salida esencialmente imposible.
    • Corrección: El MSVC++ biblioteca apoyo UTF-16 y UTF-32 para los tipos char16_t y char32_t, que podrían resolver el problema de file I/O.
    • No hay una buena respuesta. Qué uso yo supongo que depende de marco, de plataforma, de específicos requisitos de e/S, etc. En general, si uno debe admitir que no BMP, char32_t y UTF-32 parece más seguro.
    • No, la pregunta es lo que puede utilizar en lugar de wstring para UTF-16
    • convertir a UTF-32, a continuación, utilizar la cadena de<char32_t>. O, en .Uso de la red del sistema.texto.UTF32Encoding
    • a menos que, por supuesto, usted puede garantizar BMP, entonces no hay ningún problema.
    • ¿has oído hablar de los pares suplentes? UTF-16 está diseñado para ser utilizado con 16 unidades de código. Fuera de BMP está bien. Son conscientes de que los UTF-16 se puede codificar todos los puntos de código Unicode?
    • sí, estoy consciente. El problema es que muchas de las Api que utilizan wstrings no saben la diferencia. Ellos interpretan los pares suplentes como dos códigos de 16 bits de puntos. Pero dado que los pares suplentes están en el rango no válido de la BMP, son ignorados.
    • que sería una crítica de la API, pero su original punto es que wstring no es bueno para el almacenamiento de UTF-16. De todos modos, que Api se refiere. Tengo la curiosidad de saber que no son compatibles con Unicode.

  6. -3

    Esto es un poco crudo, pero ¿qué hay de leer el archivo en formato de edad bytes luego emitir el byte del búfer a wchar_t* ?

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

Dejar respuesta

Please enter your comment!
Please enter your name here