[gelöst] UNICODE in Datei schreiben



  • Ich habe diese Struktur. Von dieser Struktur habe ich ein Array mit 100 Elementen angelegt. Jedes dieser Element wird jetzt beschrieben. Danach will ich das gesamte Array in eine Datei schreiben (habe auch schon versucht das einfach nur das ganze Array anzugeben -> listFile.write((wchar_t*) &objectMeta, sizeof(objectMeta)); Hat aber auch nicht funktioniert.

    Meine Frage: Wie schreibe ich das gesamte, zuvor gefüllte Array, als UNICODE-Stream in eine Datei und wie schreibe ich diese Daten ebenso wieder in ein solches Array zurück?

    Als Nicht-UNICODE-Variante geht das ja, aber als UNICODE nicht.



  • _Bongo schrieb:

    Hat aber auch nicht funktioniert.

    Aha. Weil keine Zeilen da sind. Dass es keine geben kann hatten wir aber schon geklärt.



  • Nimm std::fstream, bzw. std::ofstream.

    Ich vermute, dass das Problem darin liegt, dass sizeof(wchar_t) != 1 ist.

    Wenn Du sizeof(mystruct) machst, bekommst Du die Anzahl der Bytes, die die Struct belegt. Schreibst Du auf ein wstream mit write, erwartet write die anzahl der wchar_t-Zeichen, die aber nicht der Anzahl der Bytes in der struct entsprechen.

    Das könnte gehen:

    listFile.write(reinterpret_cast<wchar_t*>(&objectMeta[i]), sizeof(strctEintrag)/sizeof(wchar_t));
    

    Dass ich den Cast geändert habe, liegt einfach daran, dass ich es nicht übers Herz bringe, diesen C-Style-Cast zu veröffentlichen. Das reinterpret_cast macht es deutlicher, wie kaputt das eigentlich ist.



  • Aber das Array ist voll beschrieben und in der Nicht-UNICODE-Varianten schreibt das Programm alles in die Datei und holt es auch wieder raus. Stelle ich fstream dann aber auf wfstream um, geht es nicht mehr. Das dürfte aber doch mit einem fstream-Objekt ebenso wenig klappen, wenn keine Zeilen da sind. Warum sind in der einfachen Varianten Zeilen vorhanden und in der UNICODE-Varianten plötzlich nicht mehr?



  • Das mit dem /sizeof(wchar_t) will auch nicht funktionieren.



  • wchar_t hat mit UNICODE nur indirekt zu tun!
    Schau dir die erzeugte Datei mal mit einem Hexeditor an, dann verstehst du vllt. wie ein wchar_t aufgebaut ist (Stichwort: UCS, s.a. Wide character)...

    Edit: ich nehme mal an, daß du UTF-8 Dateien erzeugen willst (welche dann auch mit einem Texteditor lesbar sind) - dafür benötigst du dann aber eine UTF-8 Implementierung (unter Windows einfach WideCharToMultiByte).



  • Auszug aus winnt.h
    typedef wchar_t WCHAR; // wc, 16-bit UNICODE character

    Was stimmt nicht an dieser Zeile, wenn wchar_t nix mit UNICODE zu tun hat? Es ist die Darstellung von Zeichen mittels 2 Bytes.



  • Was genau verstehst du denn unter Zeilen (denn bisher schreibst du ja die ganzen Strukturdaten binär dort rein, inklusive Nullterminierung etc.)?

    PS: Habe gerade meinen oberen Beitrag noch editiert.



  • Von Zeilen hat manni66 gesprochen.

    Ich arbeite die ganze Zeit mit UNICODE-Werten und will einfach nur diese Daten in jede Struktur meines Struktur-Arrays schreiben (was ja auch funzt), und diese dann anschließend in eine Datei speichern.
    Anschließend wieder aus der Datei in ein solches Array von eben solchen Strukturen zurückschreiben.

    Die sollen nicht im Texteditor lesbar sein. Ich will diese Daten aus der Datei in das Struktur-Array schreiben, und Teile dieser Daten aus jeder Struktur in ein ListBox-Steuerelement eintragen.



  • Du hast gleich im ersten Beitrag geschrieben:

    _Bongo schrieb:

    In der Datei steht aber nur eine Zeile - der Rest ist nicht da.

    Wie hast du denn überprüft, ob dort mehr drin steht?



  • Ich ging von einer Zeile aus, weil ich scheinbar alle Strukturen in die Datei geschrieben hatte, aber beim Öffnen der Datei nur eine einzige Zeile sah. Ich hatte das testweise in eine TXT-Datei geschrieben, aber nur, weil ich das in Binärdateien so schlecht ermitteln konnte.



  • _Bongo schrieb:

    Was stimmt nicht an dieser Zeile, wenn wchar_t nix mit UNICODE zu tun hat? Es ist die Darstellung von Zeichen mittels 2 Bytes.

    Hast du das hier schon gelesen?
    http://www.joelonsoftware.com/articles/Unicode.html



  • Kann ich mir bei Zeiten mal durchlesen, aber ist mit Sicherheit nicht so kompliziert, nicht so umständlich, die funktionierende Variante mit fstream durch die wfstream-Variante zu ersetzen - oder?



  • _Bongo schrieb:

    Von Zeilen hat manni66 gesprochen.

    Nein, du in deinem ersten Post.

    _Bongo schrieb:

    In der Datei steht aber nur eine Zeile - der Rest ist nicht da.



  • _Bongo schrieb:

    Kann ich mir bei Zeiten mal durchlesen, aber ist mit Sicherheit nicht so kompliziert, nicht so umständlich, die funktionierende Variante mit fstream durch die wfstream-Variante zu ersetzen - oder?

    Vermutlich nicht, ich kenne die entsprechenden APIs nicht.

    Aber: Du willst nicht "UNICODE" schreiben, sondern Text in einem bestimmten Character Encoding. Das könnte UTF-16 bzw. UCS-2 sein, oder UTF-8, oder sonstwas. Deine winnt.h-Referenz legt nahe, dass du UTF-16 meinen könntest (habe nicht viel Ahnung von Windows), aber du solltest vmtl. nochmal nachlesen, was genau du möchtest.



  • Das hier (was funktioniert):

    struct _eintrag
    {
    	long	nummer;
    	wchar_t name[30];
    	wchar_t testarray[4][150];
    }eintrag[2];
    
    int main()
    {
    	fstream	ausgabedatei;
    	bool	schalter=false;
    
    	if(schalter)
    	{
    		ausgabedatei.open("U:\\structTest.dat", ios::out | ios::binary);
    
    		eintrag[0].nummer=5146000;
    		wcscpy_s(eintrag[0].name, L"Tabelle 1");
    		wcscpy_s(eintrag[0].testarray[0], L"Pfadangabe zu Version 602 (1)");
    		wcscpy_s(eintrag[0].testarray[1], L"Pfadangabe zu Version 700 (1)");
    		wcscpy_s(eintrag[0].testarray[2], L"Pfadangabe zu Version 710 (1)");
    		wcscpy_s(eintrag[0].testarray[3], L"Pfadangabe zu Version 800 (1)");
    
    		eintrag[1].nummer=5146001;
    		wcscpy_s(eintrag[1].name, L"Tabelle 2");
    		wcscpy_s(eintrag[1].testarray[0], L"Pfadangabe zu Version 602 (2)");
    		wcscpy_s(eintrag[1].testarray[1], L"Pfadangabe zu Version 700 (2)");
    		wcscpy_s(eintrag[1].testarray[2], L"Pfadangabe zu Version 710 (2)");
    		wcscpy_s(eintrag[1].testarray[3], L"Pfadangabe zu Version 800 (2)");
    
    		for(int i=0; i < 2; i++)
    			ausgabedatei.write((char*) &eintrag[i], sizeof(eintrag[0]));
    	}
    	else
    	{
    		ausgabedatei.open("U:\\structTest.dat", ios::in);
    		ausgabedatei.read((char*) &eintrag, sizeof(eintrag[0]));
    
    		for(int i=0; i < 2; i++)
    		{
    			 cout << "Nummer: " << eintrag[i].nummer << endl;
    			wcout << "Name: " << eintrag[i].name << endl;
    			 cout << "Pfade: " << endl;
    			for(int j=0; j < 4; j++)
    				wcout << eintrag[i].testarray[j] << endl;
    
    			cout << endl;
    		}
    	}
    
    	ausgabedatei.close();
    	cin.get();
    	return 0;
    }
    

    soll so geschrieben werden (wfstream statt fstream):

    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    struct _eintrag
    {
    	long	nummer;
    	wchar_t name[30];
    	wchar_t testarray[4][150];
    }eintrag[2];
    
    int main()
    {
    	wfstream	ausgabedatei;
    	bool		schalter=false;
    
    	if(schalter)
    	{
    		ausgabedatei.open("U:\\structTest.dat", ios::out | ios::binary);
    
    		eintrag[0].nummer=5146000;
    		wcscpy_s(eintrag[0].name, L"Tabelle 1");
    		wcscpy_s(eintrag[0].testarray[0], L"Pfadangabe zu Version 602 (1)");
    		wcscpy_s(eintrag[0].testarray[1], L"Pfadangabe zu Version 700 (1)");
    		wcscpy_s(eintrag[0].testarray[2], L"Pfadangabe zu Version 710 (1)");
    		wcscpy_s(eintrag[0].testarray[3], L"Pfadangabe zu Version 800 (1)");
    
    		eintrag[1].nummer=5146001;
    		wcscpy_s(eintrag[1].name, L"Tabelle 2");
    		wcscpy_s(eintrag[1].testarray[0], L"Pfadangabe zu Version 602 (2)");
    		wcscpy_s(eintrag[1].testarray[1], L"Pfadangabe zu Version 700 (2)");
    		wcscpy_s(eintrag[1].testarray[2], L"Pfadangabe zu Version 710 (2)");
    		wcscpy_s(eintrag[1].testarray[3], L"Pfadangabe zu Version 800 (2)");
    
    		for(int i=0; i < 2; i++)
    			ausgabedatei.write(reinterpret_cast<wchar_t*>(&eintrag[i]), sizeof(eintrag[0]));
    	}
    	else
    	{
    		ausgabedatei.open("U:\\structTest.dat", ios::in);
    		ausgabedatei.read(reinterpret_cast<wchar_t*>(&eintrag[0]), sizeof(eintrag[0]));
    
    		for(int i=0; i < 2; i++)
    		{
    			 cout << "Nummer: " << eintrag[i].nummer << endl;
    			wcout << "Name: " << eintrag[i].name << endl;
    			 cout << "Pfade: " << endl;
    			for(int j=0; j < 4; j++)
    				wcout << eintrag[i].testarray[j] << endl;
    
    			cout << endl;
    		}
    	}
    
    	ausgabedatei.close();
    	cin.get();
    	return 0;
    }
    


  • Die Frage ist, warum willst Du das mit wfstream machen? Du schreibst doch keine Textdatei mit UCS-2 Daten, sondern eine Binärdatei mit Datenblöcken. Dafür ist fstream sogar besser, da hier die Zeichengröße 1 ist und du damit direkt sizeof verwenden kannst.

    Wenn Du das mit wfstream machst, so es denn funktioniert, würde die Datei exakt den gleichen Inhalt haben.



  • Ich habe sämtliche Zeilen in widechar vorliegen (Pfadangaben, Daten, ...). Von daher dachte ich, sei es sauberer, wenn ich die widechar-Daten via widechar-Filestream in eine Datei schiebe.

    Aber wenn das mit fstream ja sogar besser ist, dann belasse ich das beim fstream - funktioniert ja schließlich.

    Ich danke euch allen

    Gruß
    Kai


Anmelden zum Antworten