Как переносимо записать std:: wstring в файл?
у меня есть wstring
объявлен такой:
// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";
литерал будет UTF-8 закодирован, потому что мой исходный файл.
[EDIT: согласно Марку Рэнсому, это не обязательно так, компилятор решит, какую кодировку использовать - вместо этого предположим, что я читаю эту строку из файла, закодированного, например, в UTF-8]
Я очень хотел бы получить это в чтение файла (когда текстовый редактор установлен на правильный кодировка)
abcàdëefŸg€hhhhhhhµa
но ofstream
не очень сотрудничает (отказывается принимать wstring
параметры), и wofstream
якобы должен знать, настройки локали и кодировки. Я просто хочу вывести этот набор байтов. Как обычно это делается?
EDIT: он должен быть кросс-платформенным и не следует полагаться на кодировку UTF-8. У меня просто есть набор байтов, хранящихся в wstring
, и хотите вывести их. Это вполне может быть UTF-16, или обычный ФОРМАТ ASCII.
9 ответов
Почему бы не записать файл в двоичном формате. Просто используйте ofstream с настройкой std::ios::binary. Тогда редактор сможет его интерпретировать. Не забудьте флаг Unicode 0xFEFF в начале. Возможно, вам лучше писать с библиотекой, попробуйте один из них:
http://www.codeproject.com/KB/files/EZUTF.aspx
на std::wstring
вам нужно std::wofstream
std::wofstream f(L"C:\some file.txt");
f << str;
f.close();
std::wstring
для чего-то вроде UTF-16 или UTF-32, не UTF-8. Для UTF-8 вы, вероятно, просто хотите использовать std::string
, и напишите через std::cout
. Просто FWIW, C++0x будет иметь литералы Unicode, которые должны помочь прояснить такие ситуации.
C++ имеет средства для выполнения преобразования из широкого символа в локализованные на выходе или записи файла. использовать фасет codecvt для этой цели.
вы можете использовать standard 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 "и сделать выбор из многих referenes перечисленных пользовательские реализации codecvt.
изменить: Поскольку OP утверждает, что строка уже закодирована, все, что он должен сделать, это удалить префиксы L и "w" Из каждого маркера его кода.
существует (специфичное для 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;
}
обратите внимание, что широкие потоки выводят только переменные char *, поэтому, возможно, вам следует попробовать использовать c_str()
функция-член для преобразования std::wstring
, а затем выведите его в файл. Тогда надо, наверное, работать?
вы должны не используйте исходный файл в кодировке UTF-8, Если вы хотите написать портативный код. Извиняюсь.
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";
(Я не уверен, что это действительно вредит стандарту, но я думаю, что это так. Но даже если, для безопасности, вы не должны.)
Да, чисто с помощью std::ostream
не будет работать. Существует много способов преобразования wstring
в UTF-8. Мой любимый использует на международные компоненты для Unicode. Это большая свобода, но это здорово. Вы получите много дополнительных услуг и вещей, которые вам могут понадобиться в будущем.
из моего опыта работы с различными кодировками символов я бы рекомендовал вам иметь дело только с UTF-8 При загрузке и экономии времени. Вы находитесь в мире боли, Если вы пытаетесь сохранить внутреннее представление в UTF-8, так как один символ может быть от 1 байта до 4. Поэтому простые операции, такие как strlen, требуют просмотра каждого байта, чтобы решить len, а не выделенный буфер (хотя вы можете оптимизировать, глядя на первый байт в последовательности символов, например, 00..7Ф является один байт типа char, С2..df указывает на 2-байтовый символ и т. д.).
люди довольно часто ссылаются на "строки Юникода", когда они означают UTF-16, а в Windows wchar_t-фиксированные 2 байта. В Windows я думаю, что wchar_t просто:
typedef SHORT wchar_t;
полное представление UTF-32 4 байта редко требуется и очень расточительно, вот что должен сказать на нем стандарт Unicode (5.0):
" в среднем более 99% всех UTF-16 выражается с использованием единичных кодовых единиц... UTF-16 обеспечивает правое смешивание компактного размера с способностью отрегулировать случайный характер вне BMP"
короче говоря, используйте whcar_t в качестве внутреннего представления и выполняйте преобразования при загрузке и сохранении (и не беспокойтесь о полном Unicode, если вы не знаете, что вам это нужно).
что касается выполнения фактического преобразования, посмотрите на проект ICU:
некоторое время назад у меня была такая же проблема, и я записал решение, которое нашел в своем блоге. Возможно, вы захотите проверить его, чтобы узнать, может ли это помочь, особенно функция wstring_to_utf8.
http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t