c++ mfc utf-8 cstring cfile

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



(3)

Asegúrate de estar usando Unicode (TCHAR es wchar_t). Luego, antes de escribir los datos, conviértelos usando la función WideCharToMultiByte Win32 API.

Actualmente estoy trabajando en un programa de MFC que específicamente tiene que trabajar con UTF-8. En algún momento, tengo que escribir datos UTF-8 en un archivo; para hacer eso, estoy usando CFiles y CStrings.

Cuando escribo datos utf-8 (caracteres rusos, para ser más precisos) en un archivo, la salida se ve como

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

y etc. Esto seguramente no es utf-8. Para leer estos datos correctamente, tengo que cambiar la configuración de mi sistema; cambiar los caracteres que no son ASCII a una tabla de codificación rusa funciona, pero luego todos mis caracteres latinos que no son ASCII fallan. De todos modos, así es como lo hago.

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

¿Me estoy perdiendo de algo? ¿Debo usar algo más en su lugar? ¿Hay algún tipo de captura que me haya perdido? Estaré atento a su sabiduría y experiencia, compañeros programadores.

EDITAR: Por supuesto, como acabo de hacer una pregunta, finalmente encuentro algo que podría ser interesante, que se puede encontrar aquí . Pensé que podría compartirlo.

EDICION 2:

De acuerdo, entonces agregué la lista de materiales a mi archivo, que ahora contiene caracteres excelentes, probablemente porque no convertí mi línea a UTF-8. Para agregar el bom que hice ...

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

Y después de eso, agregué ...

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

Pero luego no puedo compilar, ya que realmente no sé cómo obtener la longitud de TestLine. strlen no parece aceptar TCHAR. Corregido, usó una longitud estática de 1000 en su lugar.

EDIT 3:

Entonces, agregué este código ...

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

Se compila bien, pero cuando voy a ver mi nuevo archivo, es exactamente lo mismo que cuando no tenía todo este nuevo código (por ejemplo: Ðàñïå ÷ àòàíî :). Siento que no di un paso adelante, aunque creo que solo una pequeña cosa es lo que me separa de la victoria.

EDIT 4:

Quité el código agregado anteriormente, como Nate me preguntó, y decidí usar su código, lo que significa que ahora, cuando agregue mi línea, tengo ...

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

Todo compila bien, pero los caracteres rusos se muestran como ???????. Acercarse, pero aún no eso. Por cierto, me gustaría agradecer a todos los que intentaron / intentaron ayudarme, es MUCHO apreciado. He estado atrapado en esto por un tiempo, no puedo esperar a que este problema desaparezca.

FINAL EDIT (Espero) Al cambiar la forma en que obtuve por primera vez mis caracteres UTF-8 (volví a codificar sin saberlo), lo cual era erróneo con mi nueva forma de generar el texto, obtuve resultados aceptables. Al agregar el carácter UTF-8 BOM al principio de mi archivo, podría leerse como Unicode en otros programas, como Excel.

¡Viva! ¡Gracias a todos!


Cuando saca datos que necesita hacer (esto supone que está compilando en modo Unicode, que es muy recomendable):

CString russianText = L"Привет мир"; CFile yourFile(_T("yourfile.txt"), CFile::modeWrite | CFile::modeCreate); CT2CA outputString(russianText, CP_UTF8); yourFile.Write(outputString, ::strlen(outputString));

Si _UNICODE no está definido (en su lugar, está trabajando en modo multibyte), necesita saber en qué página de códigos está el texto de entrada y convertirlo en algo que pueda usar. Este ejemplo muestra el trabajo con texto en ruso que está en formato UTF-16, guardándolo en 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));

Es más probable que su texto en ruso esté en alguna otra página de códigos, como KOI-8R. En ese caso, debe convertir desde la otra página de códigos a UTF-16. Luego convierta el UTF-16 en UTF-8. No puede convertir directamente de KOI-8R a UTF-8 usando las macros de conversión porque siempre intentan convertir texto angosto a la página de códigos del sistema. Entonces, la manera más fácil es hacer esto:

// 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));

No necesita una lista de materiales (es opcional, no la usaría a menos que haya una razón específica para hacerlo).

Asegúrese de leer esto : http://msdn.microsoft.com/en-us/library/87zae4a3(VS.80).aspx . Si usa CT2CA incorrectamente (por ejemplo, utilizando el operador de asignación), tendrá problemas. La página de documentación vinculada muestra ejemplos de cómo usarla y cómo no usarla.

Más información:

  • La C en CT2CA indica const . Lo uso cuando sea posible, pero algunas conversiones solo son compatibles con la versión no const (por ejemplo, CW2A ).
  • La T en CT2CA indica que está convirtiendo desde un LPCTSTR . Por lo tanto, funcionará si su código se compila con el indicador _UNICODE o no. También podría usar CW2A (donde W indica caracteres anchos).
  • La A en CT2CA indica que está convirtiendo a una cadena "ANSI" (char de 8 bits).
  • Finalmente, el segundo parámetro para CT2CA indica la página de códigos a la que está convirtiendo.

Para hacer la conversión inversa (de UTF-8 a LPCTSTR), podría hacer:

CString myString(CA2CT(russianText, CP_UTF8));

En este caso, estamos convirtiendo de una cadena "ANSI" en formato UTF-8 a un LPCTSTR. El LPCTSTR siempre se supone que es UTF-16 (si se define _UNICODE ) o la página de códigos del sistema actual (si _UNICODE no está definido).


Tendrá que convertir sWorkingLine a UTF-8 y luego escribirlo en el archivo.

WideCharToMultiByte puede convertir cadenas de Unicode a UTF-8 si selecciona la página de códigos CP_UTF8 . MultiByteToWideChar puede convertir caracteres ASCII en unicode.