Textdatei mit Unicodezeichen erstellen schlägt fehl
-
Schonmal danke dafür, ich habe den Quellcode jetzt so umgeschrieben:
#include <stdio.h> #include <windows.h> #define LOG_FILENAME TEXT("event.log") BOOL WriteLog( LPCWSTR lptsUser, LPCWSTR lptsEvent ) { HANDLE hLogfile; DWORD dwCharcount, dwBuffersize; void *pBuffer; hLogfile = CreateFile( LOG_FILENAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); if ( hLogfile == INVALID_HANDLE_VALUE ) { CloseHandle( hLogfile ); return FALSE; } // calculate size for our buffer, including lenghts of input and format string and \0 dwCharcount = wcslen( lptsUser ) + wcslen( lptsEvent ) + wcslen( L"U: E: \n" ) + 1; dwBuffersize = dwCharcount * sizeof(wchar_t); if ( dwBuffersize <= 0 ) { CloseHandle( hLogfile ); return FALSE; } pBuffer = malloc( dwBuffersize ); if ( pBuffer == NULL ) { CloseHandle( hLogfile ); return FALSE; } swprintf( (wchar_t*)pBuffer, L"U: %s E: %s\n", lptsUser, lptsEvent ); // calculate EOF OVERLAPPED ovlp; ovlp.OffsetHigh = ovlp.Offset = 0xFFFFFFFF; ovlp.hEvent = NULL; WriteFile( hLogfile, pBuffer, dwBuffersize, NULL, &ovlp ); CloseHandle( hLogfile ); free( pBuffer ); return TRUE; }Das klappt nun auch soweit, aber nur Notepad zeigt die Datei einigermaßen korrekt an, andere Editoren können das Format nicht feststellen, da ich das ja nirgendwo schreibe.
Nun also die zweite Frage, wie schreibe ich die Kodierung mit in die Datei und welche ist das überhaupt?
-
Scheinbar werden noch "überflüssige" Zeichen mit in die Datei geschrieben.
Soe sieht der Log in Notepad++ aus
http://img261.imageshack.us/img261/4641/notepadnw8.jpg
und so im normalen Notepad
http://img261.imageshack.us/img261/1489/notepad2np2.jpg
-
Hast du denn die BOM reingeschrieben?
Und deinen Code verstehe ich nicht ganz, was willst du z.B. mit der Overlapped-Struktur, wenn du die Datei nicht-overlapped öffnest? Wenn du einfach an's Ende der Datei schreiben willst, setz den Dateizeiger dahin (mit SetFilePointer und GetFileSize).
Und FILE_SHARE_WRITE würde ich nicht mit angeben, gibt doch nur Chaos.
-
Genau danach habe ich ja gefragt

Ich habe jetzt die Textdatei einmal im Editor und einmal mit meinem Programm erstellt und in meiner Version sind noch zusätzliche Zeichen, die die Datei unlesbar machen.
Hier mal die Datei als Hex-Dump:Programm schrieb:
ff fe 00 00 55 00 3a 00 20 00 74 00 65 00 73 00 74
00 31 00 20 00 50 00 3a 00 20 00 74 00 65 00 73 00
74 00 31 00 20 00 4f 00 3a 00 20 00 74 00 65 00 73
00 74 00 31 00 20 00 44 00 3a 00 20 00 74 00 65 00
73 00 74 00 31 00 0a 00 00 00Notepad schrieb:
ff fe 55 00 3a 00 20 00 74 00 65 00 73 00 74 00 31
00 20 00 50 00 3a 00 20 00 74 00 65 00 73 00 74 00
31 00 20 00 4f 00 3a 00 20 00 74 00 65 00 73 00 74
00 31 00 20 00 44 00 3a 00 20 00 74 00 65 00 73 00
74 00 31 00 0d 00 0a 00Wie man sieht, fügt mein Programm einmal nach der BOM und ans Ende 00 00 zu viel. Liegt das an den Buffer-Größen? Wenn ich beim beiden WriteFile 2 (also sizeof(wchar_t)) von der eigentlichen Buffergröße abziehe, werden die überflüssigen 00 nicht mehr geschrieben.
Nach Badestrands Hinweis sieht der Code nun wie folgt aus (und erzeugt noch die 00):
#include <stdio.h> #include <windows.h> #define LOG_FILENAME TEXT("event.log") BOOL WriteLog( LPCWSTR lptsUser, LPCWSTR lptsEvent ) { HANDLE hLogfile; DWORD dwCharcount, dwBuffersize, dwBytesWritten; void *pBuffer; hLogfile = CreateFile( LOG_FILENAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); if ( hLogfile == INVALID_HANDLE_VALUE ) { CloseHandle( hLogfile ); return FALSE; } // if creating a new log, write BOM at the beginning DWORD dwLasterror = GetLastError(); if ( dwLasterror == 0 ) { // file exists wchar_t bom[] = L"\uFEFF"; // UTF-16, big endian WriteFile( hLogfile, &bom, sizeof(bom), &dwBytesWritten, NULL ); } // calculate size for our buffer, including lenghts of input and format string and \0 dwCharcount = wcslen( lptsUser ) + wcslen( lptsEvent ) + wcslen( L"U: E: \n" ) + 1; dwBuffersize = dwCharcount * sizeof(wchar_t); if ( dwBuffersize <= 0 ) { CloseHandle( hLogfile ); return FALSE; } pBuffer = malloc( dwBuffersize ); if ( pBuffer == NULL ) { CloseHandle( hLogfile ); return FALSE; } swprintf( (wchar_t*)pBuffer, L"U: %s E: %s \n", lptsUser, lptsEvent ); // append at end of file SetFilePointer( hLogfile, 0, NULL, FILE_END ); WriteFile( hLogfile, pBuffer, dwBuffersize, &dwBytesWritten, NULL ); CloseHandle( hLogfile ); free( pBuffer ); return TRUE; }
-
Irgendwie so:
// Statt: wchar_t bom[] = L"\uFEFF"; // UTF-16, big endian // Eher: char bom[] = { 0xFE, 0xFF }; // UTF-16, big endianEin wchar_t hat keine definierte Größe, hängt afaik vom Compiler ab.
Übrigens, arbeiten x86er nicht mit Little Endian?
-
Warum machst Du es Dir so komplitziert wenn die CRT doch einen perfekten Support inkl. BOM Schreiben bietet.
http://msdn.microsoft.com/en-us/library/yeby3zcb(VS.80).aspx
Siehe encoding. Dann winfach die entsprechenden Unicode Texte ausgeben und fertig.BTW: Warum verwendest Du überhaupt sprintf? Du gibst doch nur ein paar kostante Texte aus und dazwischen jeweils einen Text., dasbekommst Du auch mit 4 Writes hin... Das umkopieren in einen eigenen Buffer mit sprintf ist absolut unnötig.
-
Das MSDN meint auch Little Endian, aber mit Notepad erstellte Dateien haben Big Endian und mein Log ist so auch lesbar.
Hier mal der letzte Stand des Codes, der soweit auch funktioniert. Jetzt muss er nur noch in's Programm eingebaut werden..
#include <stdio.h> #include <windows.h> #define LOG_FILENAME TEXT("event.log") BOOL WriteLog( PCWSTR ptsUser, PCWSTR ptsEvent ) { HANDLE hLogfile; DWORD dwCharcount, dwBuffersize, dwBytesWritten; void *pBuffer; if ( ( ptsUser == NULL ) || ( ptsEvent == NULL ) { return FALSE; } hLogfile = CreateFile( LOG_FILENAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); if ( hLogfile == INVALID_HANDLE_VALUE ) { CloseHandle( hLogfile ); return FALSE; } // if creating a new log, write BOM at the beginning DWORD dwLasterror = GetLastError(); if ( dwLasterror == 0 ) { // file exists wchar_t bom[] = L"\uFEFF"; // UTF-16, big endian if ( WriteFile( hLogfile, &bom, sizeof(bom)-sizeof(wchar_t), &dwBytesWritten, NULL ) == FALSE ) { CloseHandle( hLogfile ); return FALSE; } } // calculate size for our buffer, including lenghts of input and format string and \0 dwCharcount = wcslen( ptsUser ) + wcslen( ptsEvent ) + wcslen( L"U: E: \n" ) + 1; dwBuffersize = dwCharcount * sizeof(wchar_t); if ( dwBuffersize <= 0 ) { CloseHandle( hLogfile ); return FALSE; } pBuffer = (void*)LocalAlloc( LPTR, dwBuffersize ); if ( pBuffer == NULL ) { CloseHandle( hLogfile ); return FALSE; } if ( _snwprintf( (wchar_t*)pBuffer, dwCharcount, L"U: %s E: %s\n", ptsUser, ptsEvent ) == -1 ) { CloseHandle( hLogfile ); LocalFree( pBuffer ); return FALSE; } if ( SetFilePointer( hLogfile, 0, NULL, FILE_END ) == INVALID_SET_FILE_POINTER ) { CloseHandle( hLogfile ); LocalFree( pBuffer ); return FALSE; } if ( WriteFile( hLogfile, pBuffer, dwBuffersize-sizeof(wchar_t), &dwBytesWritten, NULL ) == FALSE ) { CloseHandle( hLogfile ); LocalFree( pBuffer ); return FALSE; } CloseHandle( hLogfile ); LocalFree( pBuffer ); return TRUE; }Ja, das ständige return ist nicht sehr schön, aber es funktioniert erstmal :p
_wfopen_s kannte ich noch nicht, daher der etwas steinige Weg.
Das Codebeispiel hier ist stark abgespeckt, im richtigen Programm ist der Formatstring schon etwas komplexer, deswegen bleibe ich auch bei der Lösung mit dem Extra-Buffer.
Ich muss doch nur den Aufruf von CreateFile druch folgendes ersetzen?#define LOG_FILENAME L"event.log" int iError; FILE fLogfile; wchar_t wcFilemode[] = L"a+"; iError = _wfopen_s( &fLogfile, LOG_FILENAME, wcFilemode ); if ( iError == EINVAL ) { return FALSE; } // usw.
-
Du musst doch fopen kennen!
Dein Open Befehl sollte auch ein encoding setzen ccs=UNICODE! Lies doch bitte mal den Link:
http://msdn.microsoft.com/en-us/library/z5hh6ee9(VS.80).aspx
-
Martin Richter schrieb:
Du musst doch fopen kennen!
Dein Open Befehl sollte auch ein encoding setzen ccs=UNICODE! Lies doch bitte mal den Link:
http://msdn.microsoft.com/en-us/library/z5hh6ee9(VS.80).aspxIch glaube zwar mich mit Windows und dem MSVC halbwegs gut auszukenne, aber dass fopen beim MSVC BOMs und Unicode im Allgemeinen versteht/unterstützt war mir auch neu.
Danke für den Hinweis übrigens
-
Das gibt es schon seit VS-2005
Und es wurde nicht wenig darüber geblogt und geschrieben.
http://blog.m-ri.de/index.php/2007/07/03/vc-2005-features-der-crt-fuer-unicode-unterstuetzung/
Das ist zwar MFC gehört aber auch mit dazu:
http://blog.kalmbachnet.de/?postid=105
http://blog.kalmbachnet.de/?postid=107
-
Hi leute
Mal ne frage:
trotz heutiger 32bit breite hatte ich mir angewöhnt bei Dateizugriffen meist nur 8bit zu nutzen. Und da ein Standardeditor (HEX, text) auch eigentlich nicht mehr braucht, warum sollte man von ANSI, UTF-8 auf höhere (ISO) standards ausweichen? Wenn man binäre datenblöcke hat, werden diese doch meistens mit einem filestream rein und rausgeschoben ??Danke schon mal für eure Antworten :xmas1:
-
@zeusosc:
Kommt immer auf die Anforderungen an.
Ich bevorzuge bei der Ausgabe von Unicode Daten in Streams UTF-8.