onatm
onatm

Reputation: 846

Querying serialized object file

Is there anyway to achieve that without loading the whole file into memory? If so, what do you suggest me to do?

Class implementation:

[Serializable()]
public class Car
{
    public string Brand { get; set; }
    public string Model { get; set; }
}

[Serializable()]
public class CarCollection : List<Car>
{
}

Serialization to file:

CarCollection cars = new CarCollection
{
    new Cars{ Brand = "BMW", Model = "7.20" },
    new Cars{ Brand = "Mercedes", Model = "CLK" }
};

using (Stream stream = File.Open("data", FileMode.Create))
{
    BinaryFormatter bin = new BinaryFormatter();
    bin.Serialize(stream, cars);
}

Upvotes: 1

Views: 927

Answers (3)

vgru
vgru

Reputation: 51274

To deserialize the collection one object at a time, you also need to serialize it one at a time.

Simplest way is to define your own generic class:

public static class StreamSerializer
{
    public static void Serialize<T>(IList<T> list, string filename)
    {
        using (Stream stream = File.Open(filename, FileMode.Create))
        {
            BinaryFormatter bin = new BinaryFormatter();

            // seralize each object separately
            foreach (var item in list)
                bin.Serialize(stream, item);
        }
    }

    public static IEnumerable<T> Deserialize<T>(string filename)
    {
        using (Stream stream = File.Open(filename, FileMode.Open))
        {
            BinaryFormatter bin = new BinaryFormatter();

            // deserialize each object separately, and 
            // return them one at a time

            while (stream.Position < stream.Length)
                yield return (T)bin.Deserialize(stream);
        }
    }
}

Then you can simply write:

CarsCollection cars = new CarsCollection
{
    new Cars{ Brand = "BMW", Model = "7.20" },
    new Cars{ Brand = "Mercedes", Model = "CLK" }
};

// note that you cannot serialize the entire list if
// you want to query without loading - it must be symmetrical

StreamSerializer.Serialize(cars, "data.bin");

// the following expression iterates through objects, processing one 
// at a time. "First" method is a good example because it
// breaks early.

var bmw = StreamSerializer
    .Deserialize<Cars>("data.bin")
    .First(c => c.Brand == "BMW");

A slightly more complex case might be if your CarsCollection belongs to a different class. In that case, you will need to implement ISerializable, but the principle is similar.

On a side note, usual convention is not to name entities in plural (i.e. Cars should be named Car).

Upvotes: 1

Petr Behensk&#253;
Petr Behensk&#253;

Reputation: 620

Generally you can use some sort of reader (StreamReader, BinaryReader, ...) together with BufferedStream.

Upvotes: 0

Myles McDonnell
Myles McDonnell

Reputation: 13335

If you serialize to XML you can use a SAX parser (XmlReader class), which will read from a stream seqentially.

Upvotes: 2

Related Questions