Prev: Which Visual Studio for 64 Bit Apps
Next: Possible to erase Something from a Bitmap in Double Buffering
From: winapi on 31 May 2010 15:23 Hi there, I am trying to save a simple "structure" for an application I am making in windows. I have been using unicode. I have been trying to save the data uisng using "fstream", not sure if this is needed when uing the windows API. Anyway, I read that you can use "wofstream" instead of just "ofstream" for wchar_t. The simple example below works with the "char" example, but not the "wchar_t" example. it just saves a blank file. I can't seem to find an example of binary data being written using wchar_t only text examples. Maybe "wofstream" does not read/write unicode as expected without further manipulation, any pointers would be most helpful. . . . . . . . #include <windows.h> #include <iostream> #include <fstream> using namespace std; // wchar_t example. // Not Working. #define FILE_NAME L"outFile.bin" struct SDATA { wchar_t *str; int num; SDATA() { str = NULL; num = 0; } }; void SaveFile(wchar_t *file) { SDATA data; data.str = L"String"; data.num = 10; wofstream fout; fout.open(file, ios::binary); fout.write((wchar_t *)(&data), sizeof(data)); fout.close(); } //========================================================================= /* // char example. // Working. #define FILE_NAME "outFile.bin" struct SDATA { char *str; int num; SDATA() { str = NULL; num = 0; } }; void SaveFile(char *file) { SDATA data; data.str = "String"; data.num = 10; ofstream fout; fout.open(file, ios::binary); fout.write((char *)(&data), sizeof(data)); fout.close(); } */ // Simple "console" test. int main(void) { SaveFile(FILE_NAME); return 0; } Thanks.
From: Jackie on 31 May 2010 18:32 On 5/31/2010 21:23, winapi wrote: > Hi there, > > I am trying to save a simple "structure" for an application I am making in > windows. > I have been using unicode. I have been trying to save the data uisng using > "fstream", not > sure if this is needed when uing the windows API. > > Anyway, I read that you can use "wofstream" instead of just "ofstream" for > wchar_t. > The simple example below works with the "char" example, but not the > "wchar_t" example. > it just saves a blank file. I can't seem to find an example of binary data > being written using > wchar_t only text examples. Maybe "wofstream" does not read/write unicode as > expected without > further manipulation, any pointers would be most helpful. . . . . . . . > > [snip] > > Thanks. > First of all, I see a few problems with your approach: * You're trying to write a pointer to a string. * I wouldn't use wofstream to write binary data, but ofstream instead. Now, I'll answer you why I think wofstream::write fails for you... Please note that: * After fout.write(), fout.good() == false (fout.eof() == true). * I am not sure but I think maybe in a 32-bit application, "fout.write((wchar_t *)(&data), sizeof(data));" would try to write (sizeof(data) characters). That's 8 wide characters in your example which again is 16 bytes. sizeof(SDATA) is only 8 bytes. I will guess that it fails because you may be writing characters that is not within the unicode character range (somewhere in the pointer to str or the integer). Going back to writing a pointer to the string... Take a look at this example memory dump of "data": ---------------------------------------- pointer to str v 000ce930 0000000a 0�...... ^ 10 ---------------------------------------- That's what you're writing to the file. To write it properly with ofstream, you could do it like this: ---------------------------------------- fout.write(data.str, lstrlenA(data.str) + sizeof(char)); fout.write(reinterpret_cast<char*>(&data.num), sizeof(int)); ---------------------------------------- You can also solve this by either using a character array in SDATA like this: ---------------------------------------- struct SDATA { char str[100]; int num; SDATA() { memset(str, 0, sizeof(str)); num = 0; } }; ---------------------------------------- Your code in SaveFile then changes to something like the following: ---------------------------------------- void SaveFile(char *file) { SDATA data; lstrcpyA(data.str, "String"); data.num = 10; ofstream fout; fout.open(file, ios::binary); fout.write(reinterpret_cast<char*>(&data), sizeof(data)); fout.close(); } ---------------------------------------- However, this way, the file will have wasted space (sizeof(SDATA) == 104 bytes) so I would use the other method if strings are of varied lengths.
From: Jackie on 31 May 2010 19:00 On 6/1/2010 00:32, Jackie wrote: > * I am not sure but I think maybe in a 32-bit application, > "fout.write((wchar_t *)(&data), sizeof(data));" would try to write > (sizeof(data) characters). That's 8 wide characters in your example > which again is 16 bytes. sizeof(SDATA) is only 8 bytes. Rephrasing that: * I think "fout.write((wchar_t *)(&data), sizeof(data));" would try to write sizeof(data) *characters*. In a 32-bit application, the pointer would be 4 bytes so (sizeof(SDATA) == 8). It would try to write 8 wide characters, which is 16 bytes. > fout.write(reinterpret_cast<char*>(&data.num), sizeof(int)); Non-important but sizeof(data.num) looks better. > lstrcpyA(data.str, "String"); Please don't use this without checking the length of the string first before trying to copy it into data.str, or a buffer overrun may occur. It would be safer to use strcpy_s if you don't check the length yourself.
From: Ulrich Eckhardt on 1 Jun 2010 03:19 winapi wrote: > I am trying to save a simple "structure" for an application I am making in > windows. I have been using unicode. I have been trying to save the data > uisng using "fstream", not sure if this is needed when uing the windows > API. Needed, no. What I'm wondering is what file format you want. Actually, if your answer is "Unicode" or "binary", I'm afraid that you don't know. This is crucial for reading and writing correctly. My suggestion is to generally go for textual representations like JSON or XML as metaformat and using UTF-8 as encoding. > Anyway, I read that you can use "wofstream" instead of just "ofstream" > for wchar_t. The simple example below works with the "char" example, > but not the "wchar_t" example. > it just saves a blank file. I can't seem to find an example of binary data > being written using > wchar_t only text examples. Maybe "wofstream" does not read/write unicode > as expected without further manipulation, any pointers would be most > helpful. . . . . . . . FYI: Unicode is _not_ a file format. > #define FILE_NAME L"outFile.bin" // Don't use macros. wchar_t const* const filename = L"outFile.bin"; > struct SDATA > { > wchar_t *str; > int num; > > SDATA() > { > str = NULL; > num = 0; > } > }; Several points: * Who owns the memory? * Use initialisation lists. * Why not use std::wstring? * Copy constructor, assignment operator, destructor? * Use ALL_UPPERCASE for macros only. Yes, the win32 API also uses it for its types, but this is commonly agreed. > void SaveFile(wchar_t *file) wchar_t const* file > { > SDATA data; > > data.str = L"String"; > data.num = 10; > > wofstream fout; > > fout.open(file, ios::binary); The "binary" only affects the handling of line endings. Further, for the record, there is no open() function taking a wchar_t string in the standard, that is an MS extension. Also, you could initialise the ofstream with the filename directly istead of calling open() separately. Oh, and I don't see you checking the results. > fout.write((wchar_t *)(&data), sizeof(data)); 1. Do not use C-style casts, you will only shoot yourself in the foot. In order to write files, you can use a buffer of unsigned chars and then format your data in there before writing it to the stream. 2. C++ IOStreams are for textual file formats generally. Plain char-streams can be used for writing arbitrary binary data though, but you must avoid the formatting functions, only unformatted ones like read() and write(). 3. Writing an address that can change with every program call to disk is useless. If you think you are writing the L"String" somewhere, be informed that you don't. Use this in order to prepare a filestream for bytewise writing: std::ofstream out(filename, std::ios_base::binary); out.imbue(std::locale::classic()); > fout.close(); > } The stream is closed automatically here, no need for that. What you should do is flush the stream and check its state afterwards, to at least detect output errors. Uli -- Sator Laser GmbH Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
From: winapi on 2 Jun 2010 16:43
Thanks for all the helpful suggestions, I will have a good look into these methods. |