7

I have to write an object in to binary file.My struct looks like this.

   Struct Company
    {
       int numberofemployees
       list of Struct Employee.
    }

    Struct Employee
    {
       string EmployeeName;
       string Designation;
    }

What is the best way to do the above operation? Regards Raju

1
  • 4
    Why is this a struct? Those don't look like good uses for struct, and I expect this is going to bite you in interesting ways. I would use a class here... Commented Apr 8, 2010 at 11:51

3 Answers 3

10

In my understanding, BinaryFormatter is the tool for this job.

Edit: As Marc explains in the comments, BinaryFormatter has certain disadvantages. He recommends protobuf-net in his blog.

Sign up to request clarification or add additional context in comments.

7 Comments

+1 Jens, that looks better than simply writing to file yourself.
Yes you do, it gives you a fighting chance to read the data back properly some day.
Honestly, BinaryFormatter is generally a really bad choice for persistence....
It is hugely brittle; it is fine as long as you never change runtime, never change your assemblies, never obfuscate, and never change the code (for example auto-props). Additionally, it is completely .NET specific (non-portable). See marcgravell.blogspot.com/2009/03/…
Oh, and it is unnecessarily verbose and CPU intensive. And consider that alternatives exist that are not brittle (they are contract-based rather than metadata-based), take fewer bytes, less CPU and are portable between different platforms...
|
8

Here is an example how you can read/write a binary file:

using System;
using System.IO;

public class BinaryFileTest {

    private static void Main() {
        FileStream fs = new FileStream("test.dat", FileMode.Create);
        BinaryWriter w = new BinaryWriter(fs);

        w.Write(1.2M);
        w.Write("string");
        w.Write("string 2");
        w.Write('!');
        w.Flush();
        w.Close();
        fs.Close();

        fs = new FileStream("test.dat", FileMode.Open);
        StreamReader sr = new StreamReader(fs);
        Console.WriteLine(sr.ReadToEnd());
        fs.Position = 0;
        BinaryReader br = new BinaryReader(fs);
        Console.WriteLine(br.ReadDecimal());
        Console.WriteLine(br.ReadString());
        Console.WriteLine(br.ReadString());
        Console.WriteLine(br.ReadChar());
        fs.Close();

    }
}

Comments

7

What exactly do you want the output to look like? You can write it manually (see Lirik's answer), or if you want runtime support, perhaps something like protobuf-net.

This would be trivial to do if you were using classes (which I expect you actually should be), but additionally protobuf-net v2 (only available as source at the moment) should work with that "as is".

For info, here is how I would do it as classes:

    public class Company
    {
        private readonly List<Employee> employees = new List<Employee>();
        public List<Employee> Employees { get { return employees;}}
    }

    public class Employee
    {
        public string EmployeeName {get;set;}
        public string Designation {get;set;}
    }

This could be decorated with serialization attributes, or (again, using protobuf-net v2) something like this test (which passes):

    [Test]
    public void CanSerializeCompany()
    {
        var model = TypeModel.Create();
        model.Add(typeof(Company), false).Add("Employees");
        model.Add(typeof(Employee), false).Add("EmployeeName", "Designation");
        model.CompileInPlace();

        Company comp = new Company {
            Employees = {
                new Employee { Designation = "Boss", EmployeeName = "Fred"},
                new Employee { Designation = "Grunt", EmployeeName = "Jo"},
                new Employee { Designation = "Scapegoat", EmployeeName = "Alex"}}
        }, clone;
        using(var ms = new MemoryStream()) {
            model.Serialize(ms, comp);
            ms.Position = 0;
            Console.WriteLine("Bytes: " + ms.Length);
            clone = (Company) model.Deserialize(ms, null, typeof(Company));
        }
        Assert.AreEqual(3, clone.Employees.Count);
        Assert.AreEqual("Boss", clone.Employees[0].Designation);
        Assert.AreEqual("Alex", clone.Employees[2].EmployeeName);
    }

(and writes 46 bytes)

It should work with private fields, structs, etc - I'd have to take a look...

If you are able to add attributes, then you don't need to set up the model manually (the first 4 lines). The rest of the code is just showing full round-trip usage.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.