web-dev-qa-db-fra.com

Lire le fichier Unicode UTF-8 dans wstring

Comment lire un fichier Unicode (UTF-8) dans wstring (s) sur la plate-forme Windows?

36
Abdelwahed

Avec la prise en charge de C++ 11, vous pouvez utiliser facette std :: codecvt_utf8 qui encapsule la conversion entre une chaîne d'octets codée UTF-8 et une chaîne de caractères UCS2 ou UCS4 et qui peuvent être utilisés pour lire et écrire des fichiers UTF-8, texte et binaire.

Pour utiliser facette vous créez généralement objet local qui encapsule les informations spécifiques à la culture sous la forme d'un ensemble de facettes qui définissent collectivement un emplacement localisé spécifique Une fois que vous avez un objet locale, vous pouvez imbue votre tampon de flux avec lui:

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

qui peut être utilisé comme ceci:

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

Vous pouvez également définir l'environnement local C++ global avant de travailler avec des flux de chaînes qui provoquera tous les appels futurs à std::locale constructeur par défaut pour renvoyer une copie des paramètres régionaux C++ globaux (vous n'avez alors pas besoin d'imprégner explicitement les tampons de flux):

std::locale::global(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
32
LihO

Selon un commentaire de @Hans Passant, la manière la plus simple est d'utiliser _ wfopen_s . Ouvrez le fichier avec le mode rt, ccs=UTF-8.

Voici une autre solution C++ pure qui fonctionne au moins avec 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");
}

À l'exception de locale::empty() (ici locale::global() pourrait également fonctionner) et de la surcharge wchar_t* Du constructeur basic_ifstream, Cela devrait même être assez conforme aux normes (où "standard" signifie C++ 0x, bien sûr).

14
Philipp

Voici une fonction spécifique à la plate-forme pour Windows uniquement:

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

Utilisez comme ça:

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

Notez que l'intégralité du fichier est chargé en mémoire, vous ne voudrez donc peut-être pas l'utiliser pour des fichiers très volumineux.

6
AshleysBrain
#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();
}
3
Shen Yu

Cette question a été abordée dans Confus à propos de std :: wstring de C++, UTF-16, UTF-8 et l'affichage des chaînes dans une interface graphique Windows . En résumé, wstring est basé sur la norme UCS-2, qui est le prédécesseur de l'UTF-16. Il s'agit d'une norme strictement à deux octets. Je crois que cela couvre l'arabe.

0
ThomasMcLeod