Working with binary
I've never done anything involving reading/writing data in binary. However, I find myself with the need to do that very thing. I have a file (.stl) that contains triangle vertex and normal information I am going to read in and build an object from. I know the format of the file, so can I just use the C++ >> operator to grab the info? Or do I need to tell the compiler to convert from binary to something else first? Also, the file has an 80 byte header that contains no pertinant information to the object. I would imagine I can just use a seekg to skip past this section?
Thanks in advance.
Quote:Original post by CyberSlag5k
so can I just use the C++ >> operator to grab the info? Or do I need to tell the compiler to convert from binary to something else first?
I think the >> operator is only for ASCII data. You have to use the read and write commands from the file stream library.
fin.read(Object, Size);
fout.write(Object, Size);
Quote:Original post by CyberSlag5k
Also, the file has an 80 byte header that contains no pertinant information to the object. I would imagine I can just use a seekg to skip past this section?
You could do that or just use something like this:
char Buffer[80];
ifstream fin;
fin.open(filename);
fin.read(&Buffer,sizeof(Buffer));
<- more reading
fin.close();
EDIT: If you haven't already I suggest you read this article.
Quote:I know the format of the file, so can I just use the C++ >> operator to grab the info?
These are for formatted IO. Binary is unformatted IO. Use the stream's read() and write() member functions. Just make sure you only process POD-types in that way.
Quote:Or do I need to tell the compiler to convert from binary to something else first?
On Microsoft platforms, it is necessary (but not sufficient!) to open the file in binary mode, to disable newline translation.
Quote:Also, the file has an 80 byte header that contains no pertinant information to the object. I would imagine I can just use a seekg to skip past this section?
Yes. Though you should rely on the header to make sure you have a file in the correct format. Headers are rarely completely useless.
I've played around with it a bit, and it seems the read function only accepts a character as a parameter. I initially tried this:
float temp;
fin.read(temp, 4);
but that didn't compile. Should I be reading in the entire set of data as a character buffer and then convert pieces of that buffer to floats? Seems like kind of a pain. Is there a better way? And aren't I going to lose some precision doing it that way? Or does specifying that 4 bytes should be read in prevent the loss of data?
[Edited by - CyberSlag5k on February 7, 2005 11:31:20 AM]
float temp;
fin.read(temp, 4);
but that didn't compile. Should I be reading in the entire set of data as a character buffer and then convert pieces of that buffer to floats? Seems like kind of a pain. Is there a better way? And aren't I going to lose some precision doing it that way? Or does specifying that 4 bytes should be read in prevent the loss of data?
[Edited by - CyberSlag5k on February 7, 2005 11:31:20 AM]
iostreams are for formatted i/o only. Don't use them for binary operations. If you want to do that sort of thing, grab their stream buffer and manipulate that directly.
A typical istream object's read() function expects a pointer to a character buffer. The quickest way to read a multi-byte variable (such as a 4-byte float) is to cast the address of that float as a char*, and tell read() to read 4 bytes into that character buffer.
float temp;fin.read((char*)&temp, sizeof(temp));
This may have portability issues (little/big-endian), but what lazy programmer cares about those? [wink] I never know, 'cause I never work with anything other than Windows.
Hmm...I'm getting some weird results. Here's roughly what I'm doing:
The format of the file is:
Unfortunately, since the file is in binary it is difficult for me to see what values should be read in, but when I output the contents of my linked lists the first dozen or so vertices are all 0's and the rest values not what I think they should be. This makes me think I'm doing something quite wrong. Any help would be appreciated.
void loadListBinary(){LinkedList vertexList;LinkedList normalList;Vector normVector;Vector tempVector;char header[80];char buffer[50];int numFacets;ifstream fin;fin.open(fileName, ios::binary);if(fin.is_open() == false)exit(333);fin.read(header, 80);fin.read(buffer, 4);numFacets = int(buffer[0]);for(int i = 0; i < numFacets; i++){fin.read(buffer, 50);normVector.setVector(buffer[0], buffer[4], buffer[8]);normalList.InsertItem(normVector);fout << normVector << endl;tempVector.setVector(buffer[12], buffer[16], buffer[20]);vertexList.InsertItem(tempVector);fout << tempVector << endl;tempVector.setVector(buffer[24], buffer[28], buffer[32]);vertexList.InsertItem(tempVector);fout << tempVector << endl; tempVector.setVector(buffer[36], buffer[40], buffer[44]);vertexList.InsertItem(tempVector); fout << tempVector << endl << endl;}}
The format of the file is:
Any text such as the creator's name (80 bytes)int equal to the number of facets in file (4 bytes)//facet 1 float normal x (4 bytes)float normal yfloat normal zfloat vertex1 x (4 bytes)float vertex1 yfloat vertex1 zfloat vertex2 xfloat vertex2 yfloat vertex2 zfloat vertex3 xfloat vertex3 yfloat vertex3 zunused (padding to make 50-bytes) //facet 2float normal xfloat normal yfloat normal zfloat vertex1 xfloat vertex1 yfloat vertex1 zfloat vertex2 xfloat vertex2 yfloat vertex2 zfloat vertex3 xfloat vertex3 yfloat vertex3 zunused (padding to make 50-bytes) //facet 3 ...
Unfortunately, since the file is in binary it is difficult for me to see what values should be read in, but when I output the contents of my linked lists the first dozen or so vertices are all 0's and the rest values not what I think they should be. This makes me think I'm doing something quite wrong. Any help would be appreciated.
Quote:Original post by TrapNo, then it'll interpret binary float values as int values, and things will still get screwed up.
Change char buffer[50]; to int buffer[13]; and divide all indices by 4 then it should work.
There are a variety of ways to get this to work. One is just reading it straight into a float value as I specified above. Another, working with the code just posted, is to change the calls to setVector() to look like this:
normVector.setVector(*((float*)(buffer + 0)), *((float*)(buffer + 4)), *((float*)(buffer + 8)));
Somehow or another, you need to make the compiler treat some data as another type of data temporarily. This is easiest to accomplish using pointer casts. If you just cast normal data (such a buffer[0] (a char) to float), it'll just convert the first 8 bits to a float number, rather than interpretting 32 bits as though they represented a float. So you need to get the address of buffer[n] (which could be "&buffer[n]", or "buffer + n") and then treat that address as though it were an address to a float, not to a char. Or if you're reading straight into a float, as in my previous post, you need to make the address to the float act like an address to a char buffer. Make sense?
Quote:Original post by AgonyQuote:Original post by TrapNo, then it'll interpret binary float values as int values, and things will still get screwed up.
Change char buffer[50]; to int buffer[13]; and divide all indices by 4 then it should work.
There are a variety of ways to get this to work. One is just reading it straight into a float value as I specified above. Another, working with the code just posted, is to change the calls to setVector() to look like this:normVector.setVector(*((float*)(buffer + 0)), *((float*)(buffer + 4)), *((float*)(buffer + 8)));
Somehow or another, you need to make the compiler treat some data as another type of data temporarily. This is easiest to accomplish using pointer casts. If you just cast normal data (such a buffer[0] (a char) to float), it'll just convert the first 8 bits to a float number, rather than interpretting 32 bits as though they represented a float. So you need to get the address of buffer[n] (which could be "&buffer[n]", or "buffer + n") and then treat that address as though it were an address to a float, not to a char. Or if you're reading straight into a float, as in my previous post, you need to make the address to the float act like an address to a char buffer. Make sense?
Right, my concerns were that I would be attempting to store the data of a float in the sizoe of a character and I would lose part of the data. I tried modifying my original code based on your first post, but the shape drawn is garbage. Here's what I have now:
void loadListBinary(){ Vector normVector; Vector tempVector; char float1, float2, float3; char header[80]; char buffer[50]; int numFacets; ifstream fin; fin.open(fileName, ios::binary); if(fin.is_open() == false) exit(333); fin.read(header, sizeof(header)); fin.read((char*)&numFacets, sizeof(numFacets)); for(int i = 0; i < numFacets; i++) { fin.read((char*)&float1, sizeof(float1)); fin.read((char*)&float2, sizeof(float2)); fin.read((char*)&float3, sizeof(float3)); normVector.setVector(float1, float2, float3); normalList.InsertItem(normVector); fin.read((char*)&float1, sizeof(float1)); fin.read((char*)&float2, sizeof(float2)); fin.read((char*)&float3, sizeof(float3)); tempVector.setVector(float1, float2, float3); vertexList.InsertItem(tempVector); fin.read((char*)&float1, sizeof(float1)); fin.read((char*)&float2, sizeof(float2)); fin.read((char*)&float3, sizeof(float3)); tempVector.setVector(float1, float2, float3); vertexList.InsertItem(tempVector); fin.read((char*)&float1, sizeof(float1)); fin.read((char*)&float2, sizeof(float2)); fin.read((char*)&float3, sizeof(float3)); tempVector.setVector(float1, float2, float3); vertexList.InsertItem(tempVector); } vertexList.ResetList(); normalList.ResetList(); fin.close();}
The shape just comes up garbage. Am I doing somewthing wrong?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement