使用JSON.NET一次一个地序列化一个对象数组

时间:2014-06-20 08:56:36

标签: c# javascript .net json json.net

我尝试将多个项目序列化为json,并将它们格式化为数组。

它基于事件,导致它的大量数据无法作为整个集合保存在内存中。但我需要将每个项目序列化为一个文件并将其格式化为数组。

_jsonWriter = new JsonTextWriter(new StreamWriter("Output.json")));
DataGatherer.ItemGathered += item =>
{
    _jsonSerializer.Serialize(_jsonWriter, item);
    _jsonWriter.Flush();
};

目前这个输出如下:

{
  "Id": 218515,
  "Name": "A"
}{
  "Id": 118647,
  "Name": "B"
}

由于序列化程序将每个项目序列化为一个对象,因此不知道它是一个数组。

那么如何告诉JSON.Net序列化程序将每个项目作为数组项处理并格式化数据如下:

[{ "Id": 218515, "Name": "A"},{"Id": 118647,"Name": "B"}]

感谢任何提示!

2 个答案:

答案 0 :(得分:4)

我会创建一个简单的JsonItemWriter类来包装JsonTextWriter。该类只需要跟踪是否有任何项目已写入输出。如果没有,请在编写项之前使用内部JsonTextWriter将StartArray写入流。关闭外部ItemWriter时,将EndArray写入流。然后更改事件处理程序以使用ItemWriter而不是JsonTextWriter。

以下是我对JsonItemWriter

的想法
class JsonItemWriter
{
    private JsonTextWriter innerWriter;
    private JsonSerializer serializer;

    public JsonItemWriter(JsonTextWriter innerWriter, JsonSerializer serializer)
    {
        this.innerWriter = innerWriter;
        this.serializer = serializer;
    }

    public void WriteItem(object item)
    {
        if (innerWriter.WriteState == Newtonsoft.Json.WriteState.Start)
        {
            innerWriter.WriteStartArray();
        }
        serializer.Serialize(innerWriter, item);
        innerWriter.Flush();
    }

    public void Close()
    {
        innerWriter.WriteEndArray();
        innerWriter.Close();
    }
}

然后设置你的事件处理程序:

_jsonWriter = new JsonTextWriter(new StreamWriter("Output.json"));
_itemWriter = new JsonItemWriter(_jsonWriter, _jsonSerializer);

DataGatherer.ItemGathered += item =>
{
    _itemWriter.WriteItem(item);
};

这是一个使用模拟DataGatherer代表你的简短演示:

class Program
{
    static void Main(string[] args)
    {
        JsonSerializer jsonSerializer = new JsonSerializer();
        JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter("Output.json"));
        JsonItemWriter itemWriter = new JsonItemWriter(jsonWriter, jsonSerializer);

        MockDataGatherer gatherer = new MockDataGatherer();
        gatherer.ItemGathered += item =>
        {
            itemWriter.WriteItem(item);
        };

        var items = new[]
        {
            new { Id = 218515, Name = "A" },
            new { Id = 118647, Name = "B" }
        };
        gatherer.SimulateReceivingItems(items);

        itemWriter.Close();

        using (StreamReader reader = new StreamReader("Output.json"))
        {
            Console.WriteLine(reader.ReadToEnd());
        }
    }
}

class MockDataGatherer
{
    public void SimulateReceivingItems(IEnumerable<object> items)
    {
        foreach (object item in items)
        {
            ItemGathered(item);
        }
    }

    public event ItemGatheredEventHandler ItemGathered;
    public delegate void ItemGatheredEventHandler(object item);
}

以上是上面的输出(注意对象现在包装在一个数组中):

[{"Id":218515,"Name":"A"},{"Id":118647,"Name":"B"}]

答案 1 :(得分:1)

为什么不建立IEnumerable<YourObject>。 它不需要占用内存中的所有集合,当您将其提供给serialiazer时,它将被解析为数组。 一种简单的方法是用简单的方式替换ItemGathered事件调用 yield return 当你