Benutzer mit den meisten Antworten
CStdioFile::WriteString bei Unicode mit Umlauten

Frage
-
Hallo an alle,
seitdem ich mein SDI-Projekt unter VS 2013 auf Unicode umstellt habe, werden die Umlaute mit der Funktion CStdioFile::WriteString nicht mehr mit dem Inhalt in eine Datei gschrieben, wie es die Schnittstelle verlangt.
Konkret wird zunächst der Text TestÄÖÜäöü so in den Text TestŽ™š„” konvertiert:
CString strTextInh = "TestÄÖÜäöü"; CStringT<char, StrTraitATL<char, ChTraitsCRT<char>>> strtTextInhULet(strTextInh.GetBuffer(UCHAR_MAX)); strtTextInhULet.AnsiToOem(); CString strTextInhULet = strtTextInhULet; // Inhalt = "TestŽ™š„”"
Zum Schreiben der Datei verwende ich diese Klasse:
// DateiASCII.h: Schnittstelle für die Klasse CDateiASCII. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_DateiASCII_H__237E9979_7754_11D5_9DF7_AA0004000806__INCLUDED_) #define AFX_DateiASCII_H__237E9979_7754_11D5_9DF7_AA0004000806__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "StringListDbh.h" class CDateiASCII { public: BOOL Vorbelegen(CString& rstrVerzeichnis, CString& rstrDatei, BOOL bVerzAnwendung); int Schreiben(CString strASCIIDatei,CStringListDbh& strlASCIIDatei); BOOL Lesen(CString strASCIIDatei, BOOL bMeldungDialog, CStringListDbh& strlASCIIDatei); CDateiASCII(); virtual ~CDateiASCII(); }; #endif // !defined(AFX_DateiASCII_H__237E9979_7754_11D5_9DF7_AA0004000806__INCLUDED_)
// DateiASCII.cpp: Implementierung der Klasse CDateiASCII. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "DateiASCII.h" #include "StringArrayDbh.h" #include <Shlwapi.h> #include "TCHAR.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// CDateiASCII::CDateiASCII() { } CDateiASCII::~CDateiASCII() { } BOOL CDateiASCII::Lesen(CString strASCIIDatei, BOOL bMeldungDialog, CStringListDbh& strlASCIIDatei) { // Die ASCII-Datei gegebenenfalls lesen und in eine Liste schreiben BOOL bLesen = FALSE; strlASCIIDatei.RemoveAll(); // alten Inhalt löschen if (strASCIIDatei != "") { CStdioFile stdiofASCIIDatei; int nVersuche = 5; int nZler = 1; do { // VS60 stdiofASCIIDatei.m_pStream = fopen(strASCIIDatei,"r"); // errno_t eKon = fopen_s(&stdiofASCIIDatei.m_pStream,strASCIIDatei,"r"); errno_t eKon = _tfopen_s(&stdiofASCIIDatei.m_pStream,strASCIIDatei,_T("r")); if (stdiofASCIIDatei.m_pStream == NULL && nZler == nVersuche) { if (bMeldungDialog) { CString strMessage = _T("Fehler beim Öffnen der Datei '") + strASCIIDatei + _T("'."); int nKon = AfxMessageBox(strMessage,MB_ICONINFORMATION | MB_OK); } return bLesen; } else if (stdiofASCIIDatei.m_pStream == NULL) { int nSekunden = 1; int nMilliSekunden = nSekunden * 1000; Sleep(nMilliSekunden); } nZler++; } while (stdiofASCIIDatei.m_pStream == NULL); CString strZeile; while (BOOL bReturn = stdiofASCIIDatei.ReadString(strZeile) != NULL) { bLesen = TRUE; strlASCIIDatei.AddTail(strZeile); } int nSchliessen = fclose(stdiofASCIIDatei.m_pStream); } return bLesen; } int CDateiASCII::Schreiben(CString strASCIIDatei, CStringListDbh&strlASCIIDatei) { // Die ASCII-Datei schreiben int nAnzWrite = 0; CStdioFile stdiofASCIIDatei; int nVersuche = 10; int nZler = 1; do { errno_t eKon = _tfopen_s(&stdiofASCIIDatei.m_pStream,strASCIIDatei,_T("w")); if (stdiofASCIIDatei.m_pStream == NULL && nZler == nVersuche) { CString strMessage = _T("Fehler beim Schreiben der Datei '") + strASCIIDatei + _T("'."); int nKon = AfxMessageBox(strMessage,MB_ICONINFORMATION | MB_OK); return nAnzWrite; } else if (stdiofASCIIDatei.m_pStream == NULL) { int nSekunden = 1; int nMilliSekunden = nSekunden * 1000; Sleep(nMilliSekunden); } nZler++; } while (stdiofASCIIDatei.m_pStream == NULL); int nAnzahl = (int)strlASCIIDatei.GetCount(); for (nZler = 0; nZler < nAnzahl; nZler++) { POSITION pZeile = strlASCIIDatei.FindIndex(nZler); CString strZeile = strlASCIIDatei.GetAt(pZeile); CString strZeileSchreiben = strZeile; strZeileSchreiben += "\n";
stdiofASCIIDatei.WriteString(strZeileSchreiben); // <----- hier der Fehler nAnzWrite++; } int nSchliessen = fclose(stdiofASCIIDatei.m_pStream); return nAnzWrite; } BOOL CDateiASCII::Vorbelegen(CString& rstrVerzeichnis, CString& rstrDatei, BOOL bVerzAnwendung) { // Die Werte vorbelegen BOOL bDebug = FALSE; if (bVerzAnwendung) { // Das Verzeichnis der Anwendung vorbelegen TCHAR szVerzeichnis[MAX_PATH]; DWORD dwModulFileName = GetModuleFileName(NULL,szVerzeichnis,MAX_PATH); if (dwModulFileName == NULL) { DWORD dwLastError = GetLastError(); CString strMessage; strMessage.Format(_T("Fehler bei GetModuleFileName: %d"),dwLastError); int nKon = AfxMessageBox(strMessage,MB_ICONINFORMATION | MB_OK); } CString strVerzeichnis; strVerzeichnis.Format(_T("%s"),szVerzeichnis); LPTSTR lpVerzeichnis = strVerzeichnis.GetBuffer(MAX_PATH); BOOL bKon = PathRemoveFileSpec(lpVerzeichnis); // Dateiname und Erweiterung entfernen strVerzeichnis.ReleaseBuffer(); CString strEntfernen = _T("Debug"); int nKonDebug = strVerzeichnis.Find(strEntfernen); // sonst teilweise Fehler bei TrimRight if (nKonDebug >= 0) { strVerzeichnis.TrimRight(strEntfernen); bDebug = TRUE; } strEntfernen = "Release"; int nKonRelease = strVerzeichnis.Find(strEntfernen); // sonst teilweise Fehler bei TrimRight if (nKonRelease >= 0) { strVerzeichnis.TrimRight(strEntfernen); } lpVerzeichnis = strVerzeichnis.GetBuffer(MAX_PATH); LPTSTR lpKon = PathAddBackslash(lpVerzeichnis); strVerzeichnis.ReleaseBuffer(); rstrVerzeichnis = strVerzeichnis; // Die Datei vorbelegen LPTSTR lpDatei = rstrDatei.GetBuffer(MAX_PATH); PathStripPath(lpDatei); // Verzeichnis entfernen rstrDatei.ReleaseBuffer(); rstrDatei = rstrVerzeichnis + rstrDatei; } else { // Das Verzeichnis der Datei übernehmen CString strVerzeichnis = rstrDatei; LPTSTR lpVerzeichnis = strVerzeichnis.GetBuffer(MAX_PATH); BOOL bKon = PathRemoveFileSpec(lpVerzeichnis); // Dateiname und Erweiterung entfernen strVerzeichnis.ReleaseBuffer(); lpVerzeichnis = strVerzeichnis.GetBuffer(MAX_PATH); LPTSTR lpKon = PathAddBackslash(lpVerzeichnis); strVerzeichnis.ReleaseBuffer(); rstrVerzeichnis = strVerzeichnis; } return bDebug; }
In der Datei steht aber dann der falsche Text Testc203 1 0.00, der dann zu einer fehlhaften Weiterverwendung der Datei führt. Ich habe im Moment keine Idee mehr für die Lösung.
Wie kann ich in meinem SDI-Projekt eine Datei beschreiben, die den gewünschten Text TestŽ™š„” enthält?
Danke im Voraus und viele Grüße
Bernd
Antworten
-
Hallo,
das kenne ich aus der Standard Bibliothek mit std::ofstream. Irgendwo kann man zwar auch die Bibliothek auf UNICODE umstellen, aber es geht auch anders.
CString ist UNICODE. Also benutze CStringA, um in die Datei zu schreiben.
Beispielhaft für std:
CString sz = L"TextÄÖÜäöü"; CStringA szA = (CStringA)sz; std::ofstream fo(szFilename); if (fo.is_open()) { fo << CStringA(sz) << " und " << szA << '\n'; } fo.close();
Gruß Guido
- Bearbeitet Guido Franzke Donnerstag, 3. Mai 2018 05:55
- Als Antwort markiert Bernd Föry Donnerstag, 3. Mai 2018 07:03
Alle Antworten
-
Hallo,
das kenne ich aus der Standard Bibliothek mit std::ofstream. Irgendwo kann man zwar auch die Bibliothek auf UNICODE umstellen, aber es geht auch anders.
CString ist UNICODE. Also benutze CStringA, um in die Datei zu schreiben.
Beispielhaft für std:
CString sz = L"TextÄÖÜäöü"; CStringA szA = (CStringA)sz; std::ofstream fo(szFilename); if (fo.is_open()) { fo << CStringA(sz) << " und " << szA << '\n'; } fo.close();
Gruß Guido
- Bearbeitet Guido Franzke Donnerstag, 3. Mai 2018 05:55
- Als Antwort markiert Bernd Föry Donnerstag, 3. Mai 2018 07:03
-
Hallo Guido,
danke für Deine Antwort. Die Informationen haben mir sehr weiter geholfen.
Hier mein neuer Programmcode entsprechend Deinen Informationen:
int CDateiASCII::Schreiben(CString strASCIIDatei, CStringListDbh& strlASCIIDatei) { // Die ASCII-Datei öffnen int nAnzWrite = 0; int nVersuche = 10; int nZler = 1; // VS2005 CStdioFile stdiofASCIIDatei; // VS2005 BOOL bOpen; std::ofstream sosASCIIDatei(strASCIIDatei); do { // VS2005 errno_t eKon = _tfopen_s(&stdiofASCIIDatei.m_pStream, strASCIIDatei, _T("w")); // VS2005 if (stdiofASCIIDatei.m_pStream == NULL && nZler == nVersuche) if (sosASCIIDatei.is_open() == FALSE && nZler == nVersuche) { CString strMessage = _T("Fehler beim Schreiben der Datei '") + strASCIIDatei + _T("'."); int nKon = AfxMessageBox(strMessage,MB_ICONINFORMATION | MB_OK); return nAnzWrite; } // VS2005 else if (stdiofASCIIDatei.m_pStream == NULL) else if (sosASCIIDatei.is_open() == FALSE) { int nSekunden = 1; int nMilliSekunden = nSekunden * 1000; Sleep(nMilliSekunden); } nZler++; // VS2005 } while (stdiofASCIIDatei.m_pStream == NULL == FALSE); } while (sosASCIIDatei.is_open() == FALSE); // Die ASCII-Datei schreiben int nAnzahl = (int)strlASCIIDatei.GetCount(); for (nZler = 0; nZler < nAnzahl; nZler++) { POSITION pZeile = strlASCIIDatei.FindIndex(nZler); CString strZeile = strlASCIIDatei.GetAt(pZeile); // VS2005 CString strZeileSchreiben = strZeile; CStringA strZeileSchreiben = (CStringA)strZeile; strZeileSchreiben += "\n"; // VS2005 stdiofASCIIDatei.WriteString(strZeileSchreiben); sosASCIIDatei << strZeileSchreiben; nAnzWrite++; } // Die ASCII-Datei schließen // VS2005 int nSchliessen = fclose(stdiofASCIIDatei.m_pStream); sosASCIIDatei.close(); return nAnzWrite; }
Viele Grüße
Bernd
-
Wie kann ich in meinem SDI-Projekt eine Datei beschreiben, die den gewünschten Text TestŽ™š„” enthält?
Indem Du zum schreiben mit CStdioFile auch einen UNICODE stream nutzt, dann sollte es wieder kompatibel sein. Die Dokumentation zu fopen_s, _wfopen_s enthält die Details dazu.
Bsp.:
CString strTextInh = _T("TestÄÖÜäöü"); CStringT<char, StrTraitATL<char, ChTraitsCRT<char>>> strtTextInhULet(strTextInh.GetBuffer(UCHAR_MAX)); strtTextInhULet.AnsiToOem(); CString strTextInhULet (strtTextInhULet); // Open the file with the specified encoding FILE *fStream; errno_t e = _tfopen_s(&fStream, _T("bsp.txt"), _T("wt,ccs=UNICODE")); if (e != 0) ; // fail CStdioFile f(fStream); // open the file from this stream f.WriteString(strTextInhULet); f.Close();
Trotzdem ist es sicher nicht verkehrt ofstream zu nutzen, bei wide character strings wäre dies allerdings nicht std::ofstream sondern std::wofstream (erspart den unschönen C-Cast... Anm.: es gibt auch passende C++ Casts) - eine t.. Variante des ofstream gibt es leider nicht, daher muss dran gedacht werden, falls doch nochmal für Multibyte kompiliert wird, dies geeignet zu behandeln.
- Gruß Florian
-
Hallo Florian,
danke für Deine Antwort.
In Deiner Version steht der gewünschte Text auch in der Datei. Leider kann aber die externe Software diese Datei nicht lesen/importieren. Darauf habe ich keinen Einfluss und ich kann auch nichts kontrollieren. Ich lasse es deshalb bei der Version von Guido.
Viele Grüße
Bernd