Sign in to follow this  
Flimflam

[.net] Binary files and .NET

Recommended Posts

Hello everyone, I've been planning to write a few tools for a future game project of mine (with directx and c++ ), and I really love how easy forms can be designed in .net, making compelling looking tools very easy to design. However there is a delema I'm facing... See, most of the files for said project are binary, and .NET doesn't seem to have much for reading and writing binary files, asside from BinaryReader/Writer. Am I really stuck reading/writing one item in a structure in order at a time using BinaryReader/Writer, or is there a better way? Thanks in advance.

Share this post


Link to post
Share on other sites
I use the BinaryReader to read in VGM files and write 8XP files which require jumping around a bit - you can seek to locations inside them, so you don't always have to read them byte-by-byte from start to end - what is it you need to do?

Share this post


Link to post
Share on other sites
Quote:
Original post by Rob Loach
I think serialization is exactly what you're looking for. There's a great article on Code Project about Serialization in C#, you might be interested in taking a look. Good luck and if you need any help with it, feel free to give me a shout.


This actually looks rather interesting, I do have a question however. Is it possible to easily (or even logical) to read this information saved in C#, from a language like C++? I'm so used to just being able to store data and structures directly from memory into files and vise versa. I know I can't do that in .NET, but any alternatives are quite acceptable.


Edit: To also give an explination of what I want to do.

Say I have this c++ struct:
typedef struct _tagNpc {
float x, y, z;
int id;
char szName[20];
} Npc;

Now in c++ I could easily go:
Npc npc;
fread(&npc, sizeof(npc), 1, fh);

I want to have a way to store a structure in such a way it can be read like that in c++, in .net. Or at least similar.

Share this post


Link to post
Share on other sites
I'd be careful with the default serialization if I were you. Its really (really, really) easy to use but it can create a lot of really irritating maintenane issues. The namespace and all sorts of other high-level symbols get entangled in the file data in a manner that can cause some major headaches down the road.

If you want to do classic random access type file operations - like arrays of structs - the easiest way to handle it is to just grit your teeth and write FromStream/ToStream functions as members of the struct and do the individual member fields one at a time like this. These will take a BinaryWriter/Reader as arguments. The reader can be a constructor or a static that returns an instance or whatever.

This is the way classic MFC serialization worked in days of yore.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by dalep
I'd be careful with the default serialization if I were you. Its really (really, really) easy to use but it can create a lot of really irritating maintenane issues. The namespace and all sorts of other high-level symbols get entangled in the file data in a manner that can cause some major headaches down the road.

If you want to do classic random access type file operations - like arrays of structs - the easiest way to handle it is to just grit your teeth and write FromStream/ToStream functions as members of the struct and do the individual member fields one at a time like this. These will take a BinaryWriter/Reader as arguments. The reader can be a constructor or a static that returns an instance or whatever.

This is the way classic MFC serialization worked in days of yore.


So you would recommend just working like this, then?

public struct vertex
{
public float x, y, z;
public uint color;

public void FromStream(BinaryReader br) {
x = br.ReadSingle();
y = br.ReadSingle();
z = br.ReadSingle();
color = br.ReadUInt32();
}

public void ToStream(BinaryWriter br) {
br.Write(x);
br.Write(y);
br.Write(z);
br.Write(color);
}
}

Share this post


Link to post
Share on other sites
The last post was mine, it didn't seem to want to log me in.

I also have another question. When defining items in a structure, is it possible to define a char array in C# of fixed size?

In relation to defining something in c++ like:

struct happy {
int i, j, k;
char szName[20];
};


Or do I need to define it as an array and later set it's size, like so:

public struct blah {
public float x, y, z;
public uint color;
public char[] name;

...

val.name = new char[20];


[Edited by - Flimflam on November 4, 2005 5:00:02 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by FlimflamI also have another question. When defining items in a structure, is it possible to define a char array in C# of fixed size?

Yes, under 2.0 anyway. You can do this:

struct happy {
int i, j, k;
unsafe fixed char szName[20];
};

Quote:

Or do I need to define it as an array and later set it's size [...]

You can also do it this way, but it does something different in memory. The first way does what you probably expect, makes a struct the size of 3 ints and 20 chars. The second makes a struct the size of your value types plus a reference - the reference will be null until you assign it.

Be aware with method 1 that you will have use unsafe and fixed blocks to access your fixed array.

Also (as to your inital queations) it is possible to do unsafe casts in c#, but it is well, unsafe. The following ought to work:

byte[] buf = //.. read it from your file;
happy h;
unsafe {
fixed ( byte* ptr = buf){
h = ((happy*)ptr)[0];
}
}

Thus avoiding member by menber reading with some danger.

Share this post


Link to post
Share on other sites
Something like that, yes. But I would do the FromStream as either a constructor or as a static that returns an instance. It makes for a tidier syntax when you loop to load the array back out of the stream. But what you have will work too.

When it comes time to serialize the array, you first write an integer that indicates how many, then loop and write each one. Reading, you first read that integer, size your array and then loop over that, reading each one. Easy as pie, very fast and tight.

.Net serialization gets appealing when you have a complex graph of objects with a lot of references one to another. That kind of thing can be a real pain to put back together coming off disk and Serialization does it all like magic. But nothing is free in this world and the hassle you save during development is revisited on you in maintenance.

Share this post


Link to post
Share on other sites

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