Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append to file using BinaryFormatter

I'm using this code

    for (int i = 0; i < 3; ++i)
    {
        List<int> tl = new List<int>();
        tl.Add(5);
        tl.Add(4);
        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Append))
        {
            var bFormatter = new BinaryFormatter();
            bFormatter.Serialize(fileStream, tl);
            //fileStream.Close();
        }

        var list = new List<int>();

        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Open))
        {
            var bFormatter = new BinaryFormatter();
            //while (fileStream.Position != fileStream.Length)
            //{
            //     list.Add((int)bFormatter.Deserialize(fileStream));
            //}
            list = (List<int>)bFormatter.Deserialize(fileStream);
            //fileStream.Close();
        }
    }

I expect .dat file will be

5 4 5 4 5 4

but it's only

5 4

also this code return also

5 4

        List<int> tl = new List<int>();
        tl.Add(5);
        tl.Add(4);
        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Append))
        {
            var bFormatter = new BinaryFormatter();
            bFormatter.Serialize(fileStream, tl);
        }

        tl.Clear();
        tl.Add(3);
        tl.Add(2);
        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Append))
        {
            var bFormatter = new BinaryFormatter();
            bFormatter.Serialize(fileStream, tl);
        }

        var list = new List<int>();

        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Open))
        {
            var bFormatter = new BinaryFormatter();
            list = (List<int>)bFormatter.Deserialize(fileStream);
        }

it looks like it de-serialize only first portion that was appended.

why data don't append?

UPDATE: So the solution is:

        var list = new List<int>();

        using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Open))
        {
            var bFormatter = new BinaryFormatter();
            while (fileStream.Position != fileStream.Length)
            {
                var t = (List<int>)(bFormatter.Deserialize(fileStream));
                list.AddRange(t);
            }
        }
like image 264
mrgloom Avatar asked Oct 23 '25 19:10

mrgloom


2 Answers

You are adding three lists of ints, one after the other, and only reading the first one back. I think what your intent may be is to append to a (single) existing list, in which case you'd have to

  1. Read your list back into memory
  2. Add your new elements
  3. Write the list back out to the file in overwrite (not append) mode
like image 146
jlew Avatar answered Oct 25 '25 10:10

jlew


BinaryFormatter is not listed as being appendable. As it happens, you can usually get away with deserializing multiple times until you get to the EOF (and merging manually), but: there are other serializers which are explicitly designed to be appendable. For example, protocol buffers is an appendable format: concatenation is identical to merge. Further: if the outer element is a list, appending to the file is identical to adding to the composes list.

With protobuf-net, this is just:

for (int i = 0; i < 3; ++i)
{
    List<int> tl = new List<int>();
    tl.Add(5);
    tl.Add(4);
    using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Append))
    {
        Serializer.Serialize(fileStream, tl);
    }

    using (var fileStream = new FileStream(@"C:\file.dat", FileMode.Open))
    {
        list = Serializer.Deserialize<List<int>>(fileStream);
    }
}

At the end of each loop iteration, list (i.e. after deserialization) has 2, then 4, then 6 elements.

like image 41
Marc Gravell Avatar answered Oct 25 '25 10:10

Marc Gravell