binary I/O

Started by
28 comments, last by Fruny 14 years, 12 months ago
I can't find a flag for opening an fstream in text mode. I guess if you don't do ios::binary then it's automatically text mode.
Advertisement
Quote:Original post by icecubeflower
Does anybody know what that capital L is?


It is the prefix for wide characters string literals.

"foo" is a const char[4].
L"foo" is a const wchar_t[4].

Quote:This page seems pretty sure that << and >> are for text format and read() write() are for binary format but it doesn't say why


On a stream, the 'text' or 'binary' flag only controls whether end-of-line character translation should be performed (text) or not (binary) when performing formatted I/O. For example, on Win32 systems, when you write a '\n' onto a "text" file stream, it really writes "\r\n" into the file. When you read back, the "\r\n" sequence is translated back into a single '\n'. Opening a file in "binary" mode disables that translation. When you write a '\n', it'll go as a '\n' into the file.


Formatted I/O is what you do when you use << and >>. The stream framework takes the value you pass it, formats it in a human-readable format (e.g. the integer 42 becomes the character sequence '4' and '2') and writes it to the stream. Conversely, when reading, it does the inverse transformation. If you have written things without delimiters (such as '\n'), when you read back, you'll get a mess (write a 4 and then a 2 and you'll read back a 42). Robustly reading formatted data is a complicated (and sometimes complex) endeavor.

Unformatted I/O (read() and write()) takes the chunk of memory you pass it and writes it 'as is' into the stream, or takes a chunk of stream and copies it back into memory. This is what you really mean by 'binary'. The piece of data are fixed-size (e.g. an int is always sizeof(int) bytes) so there are no overruns from one chunk into the next. The downside is, obviously, that the data is not human-readable. It is unformatted.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by icecubeflower
What are all those capital L's before your string literals? I've never seen those before.


I'll answer this question as it's harder to find it out if you don't know what you are looking for.

The L is a literal that means the current string or character is "wide" (most commonly associated with Unicode).

For example, if your current project is set to a "Multi-Byte Character Set", which you can change in the Visual Studio project properties under the General Tab's Character Set entry, all strings and characters are interpreted as non-wide. You will notice this when trying to use Win32 functions and if you do not have the correct strings, then you will get compiler errors. For a simple example MessageBoxA(0, L"", L"", 0) 0) will always fail to compile, where as MessageBoxW(0, "", "", 0); will only fail to compile on a Multi-Byte Character Set project.

If you execute the code: std::cout << "Hi"; you will see "Hi" printed out. If you were to execute the code: std::cout << L"Hi";, then you would not see "Hi", you would see the address of the string since cout will only output non-wide characters and strings.

If you were to execute the code: std::wcout << L"Hi";, then you would see "Hi" since wcout is "wide cout" and since you are passing in a wide string, it works properly. Likewise, you can also use std::wcout << "Hi"; and you will see "Hi" due to how the C++ operator << coupled with the special object wcout is used. You shouldn't get errors here like you would previously.

[edit]Ninja'ed by Fruny, I so didn't see that one coming [grin]
Quote:Original post by icecubeflower
Does anybody know what that capital L is?
Wide strings. Each character will be two bytes instead of one.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Quote:Original post by icecubeflower
Here's a sample of what your write function created. I thought I tried using the << >> operators with ints but I guess I didn't. So I guess it works this way.

00x80628c4100x80628c400x80628c4water1.jpg0x80628c4water2.jpg0x80628c4water3.jpg
0x80628c4water4.jpg0x80628c4water5.jpg0x80628c4water6.jpg0x80628c4water7.jpg
0x80628c4water8.jpg0x80628c4water9.jpg0x80628c4water10.jpg0x80628c4

So is this THE WAY to do it? Serialize. ios::binary. << >> operators. '\n' as delimiter and use getline()? And every other way is the dumb way? Just making sure this is the last time I have to rewrite this.

Does anybody know what that capital L is?



My mistake - I'm used to working with wide strings so I just added the L prefixes out of habit [smile]

Removing them in your code should get the serialization half to format more nicely, and in turn should get the deserialization code to work correctly. (Just make sure that if you use something like the std::hex formatter that you use it on both ends.)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by iMalc
Quote:Original post by icecubeflower
Does anybody know what that capital L is?
Wide strings. Each character will be two bytes instead of one.


wchar_t's actual size is implementation-defined. It could be one (same as a char), just as it could be four. You can only portably rely on it being sizeof(wchar_t).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:
On a stream, the 'text' or 'binary' flag only controls whether end-of-line character translation should be performed

That's it? That's all it does? That doesn't make any sense to me. Wait, hold on.
Augh! That's all it does! I took out the capital L's and did Apoch's write function and got this:
02919cartoon1.jpgcartoon2.jpgcartoon3.jpgcartoon4.jpgcartoon5.jpgcartoon6.jpgcartoon7.jpgcartoon8.jpgcartoon9.jpgcartoon10.jpgcartoon11.jpgcartoon12.jpgcartoon13.jpgcartoon14.jpgcartoon15.jpgcartoon16.jpgcartoon17.jpgcartoon18.jpgcartoon19.jpgcartoon20.jpgcartoon21.jpgcartoon22.jpgcartoon23.jpgcartoon24.jpgcartoon25.jpgcartoon26.jpgcartoon27.jpgcartoon28.jpgcartoon29.jpg


I thought binary was what was making all those 00xAADFD things. Man.

That's funny. I went and redid everything in text mode and then I realized the functions I wrote were the same as Apochs.

Except getline() wasn't working for me. The very first getline() read an empty string. And then after that it read cartoon1, cartoon2, etc. So then I switched to the >> operator and that worked. I wonder if I did it Apoch's way now in binary if getline() will work. It basically worked before, it's just in text mode somewhere between the 19, the '\n' and cartoon1 it goofed up and read an empty string.
Quote:Original post by icecubeflower
Quote:
On a stream, the 'text' or 'binary' flag only controls whether end-of-line character translation should be performed

That's it? That's all it does? That doesn't make any sense to me.

It's ... historical.

Quote:I thought binary was what was making all those 00xAADFD things. Man.


If you open a text editor and read "0xAADF", it is still text. You just formatted it as hexadecimal rather than decimal. If you open a hex editor and read AA DF, then it really is unformatted binary.

The result depends on the functions you use to write the data, not on the mode you used to open the file -- though if you open the file in text mode and try to do unformatted I/O, you are asking for trouble. :)
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Apoch's deserialization still doesn't work for me. I can do it exactly the way he does it but getline() always reads an empty string on i==0. I just changed it to the >> operator and then it works fine.

bool Anibox::Spawnbox(string anifile, ImageVault *picbox){   ifstream infile(anifile.c_str(), ios::in | ios::binary);      if(infile.fail())      return false;   delete[] ipics;   name=anifile;   infile >> itype;   infile >> isize;   infile >> iloop;   ipics = new GLuint[isize];   for(int i = 0; i < isize; ++i)   {      std::string temp;      //getline(infile, temp);      infile>>temp;      temp = "Data/Images/" + temp;      picbox->ImageLoader(temp, ipics);   }   return true;}
Yeah, another oversight on my part - when you read the last integer, it only skips past the numerals themselves in the input stream. When the next read comes along (the getline call), the next data available to be read is the \n immediately following the integer. So that gets read (which results in an empty read) and then you proceed on to the next few strings as normal.

As long as you don't have spaces in your filenames, using the >> operator should work fine.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement