A bit of binary I/O

Jarrett Billingsley kb3ctd2 at yahoo.com
Sat Jan 20 15:45:18 PST 2007


"Heinz" <billgates at microsoft.com> wrote in message 
news:eou69k$8tf$1 at digitaldaemon.com...

> The first way is to write primitives manually one by one:
>
> // primitive way
> ulong i = 9;
> char[] s = "hello world";
> myFile.writeExact(&i, i.sizeof);
> myFile.writeExact(&s, s.sizeof);
>
> Reading data:
> // Is done by reading each primitive.
> ulong i2; char[] s2;
> myFile.readExact(&i2, i2.sizeof);
> myFile.readExact(&s2, s2.sizeof);

You're writing the string wrong.  All you're doing is writing the length and 
pointer of the array data, without actually writing the data.

The Stream class (and by extension, the File class) provides functions for 
writing out every basic type:

ulong i = 9;
char[] s = "hello world";
myFile.write(i);
myFile.write(s);

...
ulong i2;
char[] s2;
myFile.read(i2);
myFile.read(s);

> The second way is to write a structure with all the primitives as members:
>
> // struct way
> struct t
> {
> ulong i;
> char[] s;
> }
>
> t mt;
> mt.i = 9;
> mt.s = "hello world";
> myFile.writeExact(&mt, mt.sizeof);
>
> Reading data:
> // We read the entire struct.
> t mt2;
> myFile.readExact(&mt2, mt2.sizeof);

Again, you're just writing out the array reference without writing its 
contents.  You have to write out each member individually.  If there were no 
reference types in the struct, this would work fine.

>
> And the third way is to write a class with all the primitives as members:
>
> // class way
> class tt
> {
> ulong i;
> char[] s;
> }
>
> tt mtt = new tt();
> mtt.i = 9;
> mtt.s = "hello world";
> ResFile.writeExact(&mtt, mtt.sizeof);
>
> Reading data:
> // We read the entire class.
> tt mtt2;
> myFile.readExact(&mtt2, mtt2.sizeof);
>

This is incorrect, and is only working because of how you've written your 
program.  You're not writing the data out at all, you're writing a class 
reference.  The 00913FC0 is just the memory address of the class instance 
that mtt points to, and when you read that address back in, you're just 
looking at the data in memory.  This program wouldn't work if you write the 
file, exited, then had another program that read the data.  You'd end up 
with a memory access violation, and none of the data in the class is 
actually written out.

If you want to write a class out to a file, a common way is to have some 
kind of generic "serialize" and "unserialize" functions for the class:

class C
{
    ulong i;
    char[] s;

    void serialize(Stream s)
    {
        s.write(i);
        s.write(s);
    }

    static C unserialize(Stream s)
    {
        C c = new C();
        s.read(c.i);
        s.read(c.s);
        return c;
    }
}

...
C c = new C();
c.i = 5;
c.s = "foo";
c.serialize(myFile);

...

C c = C.unserialize(myFile);

>
> All of these methods works perfect. I'm able to retrieve values from all 
> of them. Now lets check at the outputs:
>
> // Primitive
>
> 09 00 00 00 00 00 00 00 0B 00 00 00 A0 C7 41 00
>
> // Structure
>
> 09 00 00 00 00 00 00 00 0B 00 00 00 A0 C7 41 00
>
> // Class
>
> C0 3F 91 00
>
> My questions are:
>
> 1) What's the best method to write data (in terms of data 
> protection/encryption against reversion). The class way seems to me at 
> first look the most secure way.

As explained before, the class method is wrong, and there is no encryption 
going on here.  It's just a memory address, and you should never, ever write 
memory addresses to a file.

That being said, the best way is probably to just use the primitive .read 
and .write methods of File.  Just .. never, ever write pointers or 
references of any kind to a file.

> 2) Wich method is the faster in retrieving data?

If you implement them correctly, all three sample programs should make the 
exact same output file using the same number of writes (and read it in the 
same number of reads), and so they are all the same in terms of performance. 




More information about the Digitalmars-d-learn mailing list