更新List <t>中的现有字段并重新保存到相同的protobuf.net文件中

时间:2017-07-03 10:50:02

标签: protobuf-net

POCO有100多个字段(使用DataMember(Order = X)属性为ProtoBuf.Net序列化标记它们)。

我们需要对文件进行一些后期处理,其中一个字段的值需要调用(我们只能在读过一次后才能执行)更新并再次保存。我们正在重新启动新文件,这显然有一些IO /文件开销。

我有什么方法可以更新现有文件,其中只需要更新和保存Field&#34; X&#34;的值。希望这比从头开始生成新文件更快。

示例POCO数据结构(并且每个文件将包含~3mln这些项目)

[DataContract]
public class DataItem
{
    [DataMember(Order=1)]
    public string ProfitCentre {get; set;}

    [DataMember(Order=2)]
    public string BusinessFunction {get; set;}

    //this is the value that needs to be updated once file is written
    [DataMember(Order=3)]
    public double AdjustedAmount {get; set; } 
}

1 个答案:

答案 0 :(得分:1)

这取决于模型的结构。 protobuf格式允许append-as-update,这意味着:可以在文件的 end 处写入一个值,然后将其应用于代码模型。但是,有一个限制:它不适用于repeated元素(包括map<...>元素)。它可以应用于根对象或任意数量的optional / required子对象,但不能应用于repeated。另一个限制是您需要一个写入该值且仅 该值的API。有多种方法可以实现这一目标,例如,如果我们有:

Foo
 - Bar (field 3 of Foo)
   - Blap (field 7 of Bar)
     - X (string, field 4 of Blap)

然后 这样做的其中一种方式就是为了这个目的而拥有第二个模型 来更新X字段,如下:

[ProtoContract]
class FooUpdate {
    [ProtoMember(3)]
    public BarUpdate Bar {get;set;} = new BarUpdate();
}
[ProtoContract]
class BarUpdate {
    [ProtoMember(7)]
    public BlapUpdate Blap {get;set;} = new BlapUpdate();
}
[ProtoContract]
class BlapUpdate {
    [ProtoMember(4)]
    public string X {get;set;}
}

现在;假设我们之前在文件中写了常规 Foo,我们可以构造:

var obj = new FooUpdate { Bar = { Blap = { X = "abcdef" } } };
Serializer.Serialize(existingFile, obj);

仅附加此数据(我假设此处existingFile位于末尾,用于附加目的)。

请注意,使用&#34;条件序列化&#34;也可以实现类似的功能,但是当我们可以......没有任何东西时,将一切关闭似乎需要付出很多努力关掉。

但是,如果您要编写的数据位于repeated / map<...>字段中,则您只需重写整个文件即可。在该上下文中,append将导致其他列表元素,或者来自地图元素的 loss 数据。