Почему программное обеспечение с поддержкой Unicode не распознает символы Š и другие символы в файлах ANSI? Как это исправить?

У меня есть проект MFC, который читает и пишет из и в файлы ANSI. Набор символов приложения установлен на Unicode.

добавление
У меня нет возможности изменить / повлиять на кодировку входного и выходного файла, потому что в моем контексте речь идет о преобразователе между устаревшим программным обеспечением.
Ожидаемая кодировка символов на самом деле окна-1252.

При чтении и записи некоторых файлов я заметил, что некоторые редко используемые символы, такие как Š (0x8A) заменить на ? (0x3F) при чтении и написании их с CStdioFile, Я создал тестовый файл, чтобы увидеть, какие символы затрагиваются в диапазоне между 0x30 а также 0xFF,

Я скопировал эти символы в TestFile (В кодировке ANSI) (символы от 0x30 до 0xFF)

Структура входного файла интерпретируется Beyond Compare

И результирующий файл выглядел так этот:

Структура выходного файла интерпретируется Beyond Compare

Измененные символы находятся вокруг одного и того же региона и заменены на 0x3F '?'— начиная с 0x80 вплоть до 0x9F, Как ни странно, есть некоторые исключения, такие как 0x81, 0x8D, 0x90 а также 0x9D которые не были затронуты.

Пример кода для проверки поведения:

//prepare vars
CFileException fileException;
CStdioFile filei;
CStdioFile fileo;
CString strText;//open input file
filei.Open(TEXT("test.txt"), CFile::modeRead | CFile::shareExclusive | CFile::typeText, &fileException);

//open output file
fileo.Open(TEXT("testout.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText, &fileException);

//read and write
BOOL eof = filei.ReadString(strText) <= 0;
fileo.Write(CStringA(strText), CStringA(strText).GetLength());

//clean up
filei.Close();
fileo.Close();

Почему он это делает и что мне нужно сделать, чтобы сохранить все символы?

Отключение режима Юникод решит проблему, но, к сожалению, в моем случае это не вариант.

Резюме
Вот выдержка из вещей, которые были мне полезны из принятого ответа:

Не конвертировать из CStringW в CStringA просто вызвав его конструктор. При преобразовании из Unicode в «ANSI» (Windows1252) используйте CW2A:

CStringA strTextA(strText, CP_ACP)` //CP_ACP converts to ANSI
fileo.Write(strTextA, strTextA.GetLength());

Еще проще: используйте CStdioFile::WriteString метод вместо CStdioFile::WriteS:

fileo.Open(TEXT("testout.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeText, &fileException);
fileo.WriteString(strText);

0

Решение

Проблема в том, что по умолчанию, если вы используете CStdioFile::Open метод CStdioFile способен только читать / записывать файлы ANSI, но вы можете открыть файл-поток самостоятельно и тогда вы сможете указать правильную кодировку:

FILE* fStream = NULL;
errno_t e = _tfopen_s(&fStream, _T("C:\\Files\\test.txt"), _T("rt,ccs=UNICODE"));
if (e != 0)
return; // failed to open file
CStdioFile f(fStream);
CString sRead;
f.ReadString(sRead);
f.Close();

Если вы хотите написать файл, вам нужно использовать _T("wt,ccs=UNICODE") множество вариантов.

Другая очевидная проблема заключается в том, что вы звоните Write вместо WriteString, Там нет необходимости конвертировать CStringW в CStringA в случае WriteString, Если требуется использовать Write по какой-то причине вам придется правильно конвертировать CStringW в CStringA позвонив в CW2A() с CP_UTF8,

Вот пример кода, который использует общее назначение CFile класс и Write вместо CStdioFile а также WriteString:

CStringW sText = L"Привет мир";

CFile file(_T("C:\\Files\\test.txt"), CFile::modeWrite | CFile::modeCreate);

CStringA sUTF8 = CW2A(sText, CP_UTF8);
file.Write(sUTF8 , sUTF8.GetLength());

Пожалуйста, имейте в виду, что CFile конструктор, который открывает файл и Write метод броска CFileException тип исключений. Таким образом, вы должны обращаться с ними.

Используйте следующие параметры при открытии потоков текстовых файлов, чтобы указать тип кодировки:

  • "ccs=UNICODE" соответствует UTF-16 (Big Endian)
  • "ccs=UTF-8" соответствует UTF-8,
  • "ccs=UTF-16LE" соответствует UTF-16LE (Little Endian)
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]