Need help with binary IO

Started by
2 comments, last by Zahlman 17 years, 10 months ago
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?
Advertisement
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 dostruct 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.
Ah, that's awesome! Now that is easy. Thanks alot.
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.

This topic is closed to new replies.

Advertisement