使用BinaryFormatter附加到文件

时间:2013-07-08 11:54:14

标签: c# serialization binaryfiles

我正在使用此代码

    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();
        }
    }

我希望.dat文件是

  

5 4 5 4 5 4

但它只是

  

5 4

此代码也返回

  

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);
        }

它看起来只反序列化了附加的第一部分。

为什么数据不附加?

更新 所以解决方案是:

        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);
            }
        }

3 个答案:

答案 0 :(得分:3)

您要添加三个整数列表,一个接一个,只读取第一个。我认为你的意图可能是附加到(单个)现有列表,在这种情况下你必须

  1. 将您的列表重新读回内存
  2. 添加新元素
  3. 以覆盖(不附加)模式将列表写回文件

答案 1 :(得分:1)

BinaryFormatter未列为可附加内容。实际上,你可以通常多次反序列化,直到你进入EOF(并手动合并),但是:还有其他序列化工具 明确设计为是可以附加的。例如,协议缓冲区是可附加格式:连接与合并相同。此外:如果外部元素是列表,则附加到文件与添加到撰写列表相同。

使用protobuf-net,这只是:

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);
    }
}

在每次循环迭代结束时,list(即反序列化后)有2,然后是4,然后是6个元素。

答案 2 :(得分:1)

正如Marc Gravell所说,BinaryFormatter不可附加,这意味着您每次需要修改文件时都需要重新编译。

示例:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

class Program
{
    const string file = @"C:\temp\file.dat";

    static void Main()
    {
        for (int i = 0; i < 3; ++i)
        {
            List<int> tl = new List<int>();
            tl.Add(5);
            tl.Add(4);

            AppendToDisk(tl);
        }

        var list = ReadFromDisk<int>();

        foreach (var item in list)
        {
            Console.Write(item);
        }
    }

    private static void AppendToDisk<T>(IEnumerable<T> collection)
    {
        var existing = ReadFromDisk<T>().ToList();

        existing.AddRange(collection);

        PersistToDisk(existing);
    }

    private static void PersistToDisk<T>(ICollection<T> value)
    {
        if (!File.Exists(file))
        {
            using (File.Create(file)) { };
        }

        var bFormatter = new BinaryFormatter();
        using (var stream = File.OpenWrite(file))
        {
            bFormatter.Serialize(stream, value);
        }
    }

    private static ICollection<T> ReadFromDisk<T>()
    {
        if (!File.Exists(file)) return Enumerable.Empty<T>().ToArray();

        var bFormatter = new BinaryFormatter();
        using (var stream = File.OpenRead(file))
        {
            return (ICollection<T>)bFormatter.Deserialize(stream);
        }
    }
}