4

我正在使用此代码

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

3 回答 3

3

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

  1. 将您的列表读回内存
  2. 添加新元素
  3. 以覆盖(非附加)模式将列表写回文件
于 2013-07-08T12:01:35.897 回答
1

BinaryFormatter未列为可附加。碰巧的是,您通常可以多次反序列化,直到到达 EOF(并手动合并),但是:还有其他序列化程序被明确设计为可附加的。例如,protocol buffers 是一种可附加格式:连接与合并相同。此外:如果外部元素是列表,则附加到文件与添加到 composes 列表相同。

使用 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 个元素。

于 2013-07-08T12:19:07.757 回答
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);
        }
    }
}
于 2013-07-08T12:25:13.447 回答