Sign in to follow this  

Need help with binary IO

This topic is 4204 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Okay, I've always kind of neglected IO... I can do some text IO, but I want to learn to do binary so my saved game files can't be tampered with as easily. Also, I've heard it's easier. Well... Here's some code from my book:
struct status
{
    char name[80];
    float balance;
    unsigned long account_number;
};

void main(void)
{
    struct status acc;
    strcopy(acc.name, "Lars Klander");
    acc.balance = 1234.56;
    acc.account_number = 98765432;
    ofstream outbal("balance.asc", ios::out | ios::binary);
    if(!outbal)
    {
        cout << "Cannot open output file." << endl;
        exit (1);
    }
    outbal.write((unsigned char *) &acc, sizeof(struct status));
    outbal.close();
}

Well, it would be awesome if it was that easy, but it didn't work when I tried it. And I can't see how it could considering acc is a structure... So I tried writing each variable one at a time. The name writes easy enough. But for the integer I split it into four unsigned chars by bit shifting each section of 8 bits left to the very end (to get rid of the 1s on the left), then all the way to the right. And for the float, when I tried to bit shift it, I got errors... It seems as if my compilers telling me I can't bit shift floats. Well. Am I like going about this the wrong way? As I said, IO is not my strong suit and I don't know much about this. So is there an easier/better/more correct way to write to a binary file?

Share this post


Link to post
Share on other sites
I think that book is trying to teach you C AND C++ mixed together at once... More like C+.

Anyways, in C there was this problem:

struct t {
int a;
};

t m; // can't do this, it won't know about t
// so you do
struct t m; // now it knows that t is a struct

// this can be taken away by:
typedef struct {
int a;
} t;

t m; // it's fine, t is now a typedef for it




You should take out the "struct" from struct t acc; and sizeof(struct t);. C++ doesn't have that problem.

EDIT: Don't change everything into a char, just cast it's address:

struct t {
int a;
other_POD b;
};

os.write(reinterpret_cast<char*>(&my_t), sizeof(my_t));


Since each char is a byte, and sizeof returns the size in bytes, it's easier to know the address in bytes rather than something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by K A Z E
Okay, I've always kind of neglected IO... I can do some text IO, but I want to learn to do binary so my saved game files can't be tampered with as easily. Also, I've heard it's easier. Well... Here's some code from my book:
*** Source Snippet Removed ***


Throw your book away. Now. Burn it. I feel sick looking at that code.

But I will clutch a hot water bottle to my tummy long enough to fix it:


struct status {
std::string name;
float balance;
unsigned long account_number;
status(const std::string& name, float balance, unsigned long account_number):
name(name), balance(balance), account_number(account_number) {}
};

template<typename T>
void write_primitive(ostream& os, const T& value) {
os.write(reinterpret_cast<unsigned char*>(&value), sizeof(T));
}

void write_string_binary(ostream& os, const std::string& s) {
write_primitive(os, s.length());
os.write(s.c_str(), s.length());
}

int main() {
status acc("Lars Klander", 1234.56, 98765432);
ofstream outbal("balance.asc", ios::out | ios::binary);
if(outbal) {
cout << "Cannot open output file." << endl;
exit(1);
}
write_string_binary(outbal, acc.name);
write_primitive(outbal, acc.balance);
write_primitive(outbal, acc.account_number);
}



Please note how I handle the string: I output a *length count first*. You *can* output a POD containing a char[] in the indicated way, but it doesn't treat the char[] as "a string", but as the array - and writes out all 80 characters, most of which are garbage.

The code as given should have "worked" for writing, but just perhaps not produced the file contents you expected.

You should, as I commonly say, "Stop. Read this." (And also this.) And also note that the "mode" with which a file is opened is a completely different thing from the "mode" in which you write the data. Nothing stops you from using operator<< on a "binary file" (fstream opened with ios::binary), or .write() on a "text file" - it's just that you usually don't want to.

Share this post


Link to post
Share on other sites

This topic is 4204 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this