reading binary files? (I know, I know)

Started by
8 comments, last by Vopisk 17 years, 9 months ago
OK, I don't understand why this is choosing not to work. I have a binary file that I wrote integers 22, 17, and 1 to. There is no problem with this file. I load it up in a hex editor and I can see those 3 numbers fine. Yet, I cannot seem to get those numbers back out in a C++ program.

std::ifstream LayoutSource;
int MapDimension[3];
int Current = 0;
LayoutSource.open(FileName.append(".map").c_str(), std::ios::binary);
LayoutSource.read((char*)(&MapDimension[0]), sizeof(int));
LayoutSource.read((char*)(&MapDimension[1]), sizeof(int));
LayoutSource.read((char*)(&MapDimension[2]), sizeof(int));
printf("MAPDIMENSIONS=%d x %d x %d\n", MapDimension[0], MapDimension[1], MapDimension[2]);



And what do I get out? MAPDIMENSIONS=-858993460 x -858993460 x -858993460 Every. Single. Time. It almost looks like an address but why? I have tried everything I can think of. I tried loading into plain integers. I tried loading into pointers to integers. I tried unsigned integers even though it wrote signed ones just fine. I used seek() to force it to the beginning. I tried several variations on the read statement that I found in various tutorials, most of which wouldn't even compile (VC++ _demands_ I cast to char* - it won't take unsigned char or just a plain reference). I just don't know how to actually get the fricking numbers out of it and it;s driving me up the wall. I'd like to void stooping to MFC's file classes in a bid to keep it cross platform but that's not more important than my sanity...
Advertisement
How are you outputting data to the file? I suspect your 'binary file' isn't actually a binary file.
1) you can shorten the code:
LayoutSource.read ( MapDimension, sizeof(int)*3 );
2) "read it like you wrote it". Make sure you wrote out the data like so:
LayoutSource.write ( MapDimension, sizeof(int)*3 );
The file just isn't opened(it doesn't exist), so you don't actually read anything. The value you're getting is 0xcccccccc, which is the value variables are initialized to in debug build. I don't know why the file doesn't open, probably a mistyping of the name, or you have specified the wrong path or something like that.
		std::ofstream ofs;		int tile;		ofs.open("./graphics/MapTiles.map", std::ios::binary);		tile = 22;		ofs.write((char*)(&tile), sizeof(int));		tile = 17;		ofs.write((char*)(&tile), sizeof(int));		tile = 1;		ofs.write((char*)(&tile), sizeof(int));		for (int rowt = 0; rowt < 22; rowt++)		{			tile = 1;			ofs.write((char*)(&tile), sizeof(int));		}		for (int m = 0; m < 15; m++)		{			tile = 1;			ofs.write((char*)(&tile), sizeof(int));			for (int w = 0; w < 20; w++)			{				tile = 0;				ofs.write((char*)(&tile), sizeof(int));			}			tile = 1;			ofs.write((char*)(&tile), sizeof(int));		}		for (int rowb = 0; rowb < 22; rowb++)		{			tile = 1;			ofs.write((char*)(&tile), sizeof(int));		}		ofs.close();


That's how I wrote the file. It's 3 dimension integers followed 22x17 tile index integers (representing a "map" of 20x15 with a 1 tile wall around it). I have it loaded in a hex editor and VC++2005 to confirm this and it is in fact the correct number of bytes for 377 integers (1508 to be exact).

I'll go one better here and show you how I open the file for reading. Keep in mind "e" is my engine variable:

e.InitializeMap("./graphics/MapTiles");void InitializeMap (std::string FileName)


I just found the error by the way. All it ever takes is 1 look-how-dumb-I-am post!

In the InitializeMap() function, I have it opening another file for the tile graphics. Apparently, what it chooses to to do is append ".tls" to get "MapTiles.tls", which is correct, but then append ".map" to "MapTiles.tls", which is incorrect. Here I was under the impression string.append() would do the sane thing and return a new string. Why in the world would you return a reference to yourself?

So Mikeman is right. If C++ were a person, I'd be fitting it for cement shoes right about now. Thanks everybody.
Quote:
Here I was under the impression string.append() would do the sane thing and return a new string. Why in the world would you return a reference to yourself?


So you can write things like "string.append(str1).append(str2)"?

string.append() does the sane thing. It does exactly what the name implies: it appends the sequence passed as a parameter to the end of the caller sequence. If you want to concanate two strings and get a new one as a result, just use the '+' operator.
Quote:Original post by RKillian
In the InitializeMap() function, I have it opening another file for the tile graphics. Apparently, what it chooses to to do is append ".tls" to get "MapTiles.tls", which is correct, but then append ".map" to "MapTiles.tls", which is incorrect. Here I was under the impression string.append() would do the sane thing and return a new string. Why in the world would you return a reference to yourself?


So that operator chaining can work.

string foo("foo");foo.append("bar").append("baz"); // works because the first append yields a// reference-to-self, which then has the second append call applied.cout << foo << endl; // "foobarbaz"


But honestly, I would just do it with operator+ ;)

LayoutSource.open((FileName + ".tls").c_str(), std::ios::binary);LayoutSource.close();LayoutSource.open((FileName + ".map").c_str(), std::ios::binary);


This is quite explicit about not mutating FileName, because that's the general contract of the "non-immediate" binary operators. If you wrote '+=' instead of '+', you would expect (correctly) FileName to be modified.

Of course, you should always read the docs anyway :)

EDIT: Actually, the name '.append()' quite clearly communicates the nature of the function. The convention is that member functions that primarily *do something with or to the object* are named according to the *action*, while member functions that primarily *return the result of a calculation* are named according to a *description of the returned value*. So you'd expect '.add()' to be mutating and '.sum()' to be "calculating".

[Edited by - Zahlman on July 2, 2006 2:22:34 AM]
Maybe it was a typo but...

Quote:
I'll go one better here and show you how I open the file for reading. Keep in mind "e" is my engine variable:
e.InitializeMap("./graphics/MapTiles");void InitializeMap (std::string FileName)



Maybe I'm wrong, but I'm pretty sure you should be opening the file to read in binary mode, so that you get something intelligible out of it. Unless your InitializeMap function takes care of that, otherwise, ignore me.
Quote:Original post by Vopisk
Maybe it was a typo but...

Quote:
I'll go one better here and show you how I open the file for reading. Keep in mind "e" is my engine variable:
e.InitializeMap("./graphics/MapTiles");void InitializeMap (std::string FileName)



Maybe I'm wrong, but I'm pretty sure you should be opening the file to read in binary mode, so that you get something intelligible out of it. Unless your InitializeMap function takes care of that, otherwise, ignore me.

If you're talking about the C-string/std::string difference, its fine - a std::string object will be implicity constructed from the C-string. It essentially acts the same as the following code -

e.InitializeMap( std::string( "./graphics/MapTiles" ) );
Quote:Original post by Mushu
Quote:Original post by Vopisk
Maybe it was a typo but...

Quote:
I'll go one better here and show you how I open the file for reading. Keep in mind "e" is my engine variable:
e.InitializeMap("./graphics/MapTiles");void InitializeMap (std::string FileName)



Maybe I'm wrong, but I'm pretty sure you should be opening the file to read in binary mode, so that you get something intelligible out of it. Unless your InitializeMap function takes care of that, otherwise, ignore me.

If you're talking about the C-string/std::string difference, its fine - a std::string object will be implicity constructed from the C-string. It essentially acts the same as the following code -

e.InitializeMap( std::string( "./graphics/MapTiles" ) );


No, I was referring to the std::ios::binary|std::ios::in. I imagine that the initialize map function is taking care of this behind the scenes, but since he's getting garbage on the read, it would stand to reason that perhaps, the call to make the fstream read in binary mode was simply overlooked, looking back though, it would appear that that is all in order.

This topic is closed to new replies.

Advertisement