UTF-8, CString и CFile? (C++, MFC)



В настоящее время я работаю над программой MFC, которая специально должна работать с UTF-8. В какой-то момент мне нужно записать данные UTF-8 в файл; для этого я использую CFiles и CStrings.



Когда я пишу utf-8 (русские символы, чтобы быть более точным) данные в файл, вывод выглядит следующим образом



Ðàñïå÷àòàíî:
Ñèñòåìà
Ïðîèçâîäñòâî


И т. д. Это определенно не utf-8. Чтобы правильно прочитать эти данные, мне нужно изменить настройки системы; изменение символов, отличных от ASCII, на русскую таблицу кодировки действительно работает, но тогда все мои латинские символы, основанные не на ascii, терпят неудачу.
Во всяком случае, так я это делаю.



CFile CSVFile( m_sCible, CFile::modeCreate|CFile::modeWrite);
CString sWorkingLine;
//Add stuff into sWorkingline
CSVFile.Write(sWorkingLine,sWorkingLine.GetLength());
//Clean sWorkingline and start over


Я что-то упустил? Может, мне лучше использовать что-нибудь другое? Есть ли какой-то подвох, который я упустил?
Я буду настроен на вашу мудрость и опыт, товарищи программисты.



Править:
Конечно, поскольку я только что задал вопрос, я, наконец, нахожу что-то, что может быть интересным, что можно найти здесь. Я подумал, что могу поделиться им.



Правка 2:



Хорошо, поэтому я добавил: BOM к моему файлу, который теперь содержит китайский символ, вероятно, потому, что я не преобразовал свою строку в UTF-8. Чтобы добавить bom я сделал...



char BOM[3]={0xEF, 0xBB, 0xBF};
CSVFile.Write(BOM,3);


И после этого, я добавил...



    TCHAR TestLine;
//Convert the line to UTF-8 multibyte.
WideCharToMultiByte (CP_UTF8,0,sWorkingLine,sWorkingLine.GetLength(),TestLine,strlen(TestLine)+1,NULL,NULL);
//Add the line to file.
CSVFile.Write(TestLine,strlen(TestLine)+1);


но тогда я не могу компилировать, так как я действительно не знаю, как получить длину тестовой строки. похоже, стрлен не принимает Чара.
Исправлено, вместо этого используется статическая длина 1000.



Правка 3:



Итак, я добавил этот код...



    wchar_t NewLine[1000];
wcscpy( NewLine, CT2CW( (LPCTSTR) sWorkingLine ));
TCHAR* TCHARBuf = new TCHAR[1000];

//Convert the line to UTF-8 multibyte.
WideCharToMultiByte (CP_UTF8,0,NewLine,1000,TCHARBuf,1000,NULL,NULL);

//Find how many characters we have to add
size_t size = 0;
HRESULT hr = StringCchLength(TCHARBuf, MAX_PATH, &size);

//Add the line to the file
CSVFile.Write(TCHARBuf,size);


Он прекрасно компилируется, но когда я иду смотреть на мой новый файл, это точно так же, как когда у меня не было всего этого нового кода (например : Ðàñïå÷àòàíî:). Такое чувство, что я не сделал ни шагу вперед, хотя, наверное, лишь малая толика отделяет меня от победы.



Правка 4:



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

        CT2CA outputString(sWorkingLine, CP_UTF8);

//Add line to file.
CSVFile.Write(outputString,::strlen(outputString));


Все компилируется нормально, но русские символы показаны как ???????. Подбираюсь ближе, но все еще нет тот.
Кстати, я хотел бы поблагодарить всех, кто пытался / пытается помочь мне, это очень ценится. Я застрял на этом уже некоторое время, я не могу дождаться, когда эта проблема исчезнет.



Окончательное редактирование (я надеюсь)
Изменив способ, которым я впервые получил свои символы UTF-8 (я повторно закодировал, на самом деле не зная), что было ошибкой с моим новым способом вывода текста, я получил приемлемые результаты. Добавляя символ BOM UTF-8 в начало моего файла, он может быть прочитан как Unicode в других программах, таких как Превосходить.



Ура! Спасибо вам всем!

744   3  

3 ответов:

Когда вы выводите данные, которые вам нужно сделать (это предполагает, что вы компилируете в режиме Unicode, что настоятельно рекомендуется):

CString russianText = L"Привет мир";

CFile yourFile(_T("yourfile.txt"), CFile::modeWrite | CFile::modeCreate);

CT2CA outputString(russianText, CP_UTF8);
yourFile.Write(outputString, ::strlen(outputString));

Если _UNICODE Не определен (вместо этого вы работаете в многобайтовом режиме), вам нужно знать, на какой кодовой странице находится ваш вводимый текст, и преобразовать его во что-то, что вы можете использовать. В этом примере показана работа с русским текстом в формате UTF-16, сохранение его в UTF-8:

// Example 1: convert from Russian text in UTF-16 (note the "L"
// in front of the string), into UTF-8.
CW2A russianTextAsUtf8(L"Привет мир", CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));

Скорее всего, ваш русский текст находится на какой-то другой кодовой странице, например KOI-8R. In в этом случае вам нужно преобразовать другую кодовую страницу в UTF-16. Затем преобразуйте UTF-16 в UTF-8. Вы не можете конвертировать непосредственно из KOI-8R в UTF-8 с помощью макросов преобразования, потому что они всегда пытаются преобразовать узкий текст на системную кодовую страницу. Так что самый простой способ сделать это:

// Example 2: convert from Russian text in KOI-8R (code page 20866)
// to UTF-16, and then to UTF-8. Conversions between UTFs are
// lossless.
CA2W russianTextAsUtf16("\xf0\xd2\xc9\xd7\xc5\xd4 \xcd\xc9\xd2", 20866);
CW2A russianTextAsUtf8(russianTextAsUtf16, CP_UTF8);
yourFile.Write(russianTextAsUtf8, ::strlen(russianTextAsUtf8));

Вам не нужна спецификация (она необязательна; я бы не стал ее использовать, если бы не было конкретной причины для этого).

Убедитесь, что Вы читаете это : http://msdn.microsoft.com/en-us/library/87zae4a3 (VS.80).aspx . если вы неправильно используете CT2CA (например, используя оператор присваивания), вы столкнетесь с проблемами. На странице связанной документации приведены примеры того, как использовать и как не использовать его.

Дополнительная информация:

  • С в CT2CA указывается const. Я использую его, когда это возможно, но некоторые преобразования поддерживают только неконстантную версию (например, CW2A).
  • Т in CT2CA означает, что вы преобразуете из в LPCTSTR. Таким образом, он будет работать независимо от того, компилируется ли ваш код с флагом _UNICODE или нет. Вы также можете использовать CW2A (где W указывает на широкие символы).
  • А in CT2CA указывает, что выполняется преобразование в строку" ANSI " (8-битный символ).
  • Наконец, второй параметр в CT2CA указывает кодовую страницу, на которую выполняется преобразование.

К выполните обратное преобразование (из UTF-8 в LPCTSTR), вы можете сделать:

CString myString(CA2CT(russianText, CP_UTF8));

В этом случае мы преобразуем из строки "ANSI" в формате UTF-8 в LPCTSTR. LPCTSTR всегда предполагается UTF-16 (если _UNICODE определен) или текущая кодовая страница системы (если _UNICODE Не определен).

Вам нужно преобразовать sWorkingLine в UTF-8, а затем записать его в файл.

WideCharToMultiByte может конвертировать строки юникода в UTF-8, Если вы выберете кодовую страницу CP_UTF8. MultiByteToWideChar может конвертировать символы ASCII в unicode.

Убедитесь, что вы используете Unicode (TCHAR-это wchar_t). Затем, прежде чем записывать данные, преобразуйте их с помощью функции Widechartomultibyte Win32 API.

Comments

    Ничего не найдено.