Как переносить std:: wstring в файл?

У меня есть wstring, объявленный как таковой:

// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

Литерал будет кодироваться в кодировке UTF-8, потому что мой исходный файл.

[EDIT: Согласно Mark Ransom, это не обязательно так, что компилятор решит, какую кодировку использовать. Предположим, что я прочитал эту строку из файла, закодированного, например. UTF-8]

Я бы очень хотел, чтобы это было в файле чтения (когда текстовый редактор установлен на правильную кодировку)

abcàdëefŸg€hhhhhhhµa

но ofstream не очень кооперативен (отказывается принимать параметры wstring), а wofstream предположительно должен знать настройки языка и кодировки. Я просто хочу вывести этот набор байтов. Как обычно это делается?

EDIT: он должен быть кросс-платформой, а не должен полагаться на кодировку UTF-8. У меня просто есть набор байтов, хранящихся в wstring, и хочу их вывести. Это вполне может быть UTF-16 или простой ASCII.

Ответы

Ответ 1

Почему бы не записать файл как двоичный файл. Просто используйте streamstream с двоичной установкой std:: ios::. Редактор должен уметь его интерпретировать. Не забывайте флаг Unicode 0xFEFF в начале. Возможно, вам лучше написать библиотеку, попробуйте один из них:

http://www.codeproject.com/KB/files/EZUTF.aspx

http://www.gnu.org/software/libiconv/

http://utfcpp.sourceforge.net/

Ответ 2

Для std::wstring вам нужно std::wofstream

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();

Ответ 3

std::wstring - это что-то вроде UTF-16 или UTF-32, а не UTF-8. Для UTF-8 вы, вероятно, просто хотите использовать std::string и выписать через std::cout. Просто FWIW, С++ 0x будет иметь литералы из Юникода, что должно помочь прояснить ситуации вроде этого.

Ответ 4

С++ имеет средства для выполнения преобразования от широкого символа к локализованному на выходе или записи файла. Используйте для этого facecvt facet.

Вы можете использовать стандартные std:: codecvt_byname или нестандартную реализацию codecvt_facet .

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.imbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

Остерегайтесь того, что на некоторых платформах codecvt_byname может выпустить преобразование только для локалей, установленных в системе. Поэтому я рекомендую искать stackoverflow для "utf8 codecvt" и сделайте выбор из многих реферансов, реализованных в пользовательских реализациях codecvt.

EDIT: Поскольку OP утверждает, что строка уже закодирована, все, что он должен сделать, это удалить префиксы L и "w" из каждого символа его кода.

Ответ 5

Существует (для Windows) решение, которое должно работать для вас здесь. В основном, конвертируйте wstring в кодовую страницу UTF-8, а затем используйте ofstream.

#include < windows.h >

std::string to_utf8(const wchar_t* buffer, int len)
{
        int nChars = ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                NULL,
                0,
                NULL,
                NULL);
        if (nChars == 0) return "";

        string newbuffer;
        newbuffer.resize(nChars) ;
        ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                const_cast< char* >(newbuffer.c_str()),
                nChars,
                NULL,
                NULL); 

        return newbuffer;
}

std::string to_utf8(const std::wstring& str)
{
        return to_utf8(str.c_str(), (int)str.size());
}

int main()
{
        std::ofstream testFile;

        testFile.open("demo.xml", std::ios::out | std::ios::binary); 

        std::wstring text =
                L"< ?xml version=\"1.0\" encoding=\"UTF-8\"? >\n"
                L"< root description=\"this is a naïve example\" >\n< /root >";

        std::string outtext = to_utf8(text);

        testFile << outtext;

        testFile.close();

        return 0;
}

Ответ 6

Обратите внимание, что в широких потоках выводятся только переменные char *, поэтому, возможно, вам стоит попробовать использовать функцию-член c_str() для преобразования std::wstring, а затем вывести его в файл. Тогда это должно сработать?

Ответ 7

У меня была такая же проблема некоторое время назад, и я написал решение, которое я нашел в своем блоге. Возможно, вы захотите проверить его, если это поможет, особенно функция wstring_to_utf8.

http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t

Ответ 8

Не следует использовать исходный файл с кодировкой UTF-8, если вы хотите написать переносимый код. К сожалению.

  std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

(Я не уверен, что это действительно повредит стандарт, но я думаю, что это так. Но даже если, чтобы быть в безопасности, вы не должны.)

Да, чистое использование std::ostream не будет работать. Существует много способов преобразования wstring в UTF-8. Мой любимый использует Международные компоненты для Юникода. Это большая библиотека, но это здорово. Вы получаете много дополнительных услуг и вещей, которые вам могут понадобиться в будущем.

Ответ 9

Из моего опыта работы с разными кодировками символов я бы рекомендовал вам работать с UTF-8 при загрузке и сэкономить время. Если вы пытаетесь сохранить внутреннее представление в UTF-8, вы можете испытывать боль, поскольку один символ может быть от 1 байт до 4. Такие простые операции, как strlen, требуют рассмотрения каждого байта, чтобы решить len, а не (хотя вы можете оптимизировать, посмотрев на первый байт в последовательности char, например 00..7f - это один байт char, c2..df указывает 2 байта char и т.д.).

Люди довольно часто ссылаются на "строки Unicode", когда они означают UTF-16, а в Windows wchar_t - фиксированные 2 байта. В Windows я думаю, что wchar_t просто:

typedef SHORT wchar_t;

Полное представление байтов UTF-32 4 байтов редко требуется и очень расточительно, вот что должен сказать об этом Unicode Standard (5.0):

"В среднем более 99% всех UTF-16 выражается с использованием единых кодовых блоков... UTF-16 обеспечивает правильное сочетание компактных размеров с возможностью обработки случайного символа вне BMP"

Короче говоря, используйте whcar_t как свое внутреннее представление и делайте конверсии при загрузке и сохранении (и не беспокойтесь о полном Unicode, если не знаете, что вам это нужно).

Что касается выполнения фактического преобразования, посмотрите проект ICU:

http://site.icu-project.org/