如何在Protbuf-net中写入固定长度的记录

本文关键字:记录 Protbuf-net | 更新日期: 2023-09-27 17:57:03

这是我使用Protobuf-net序列化的代码的主要部分。 我有大量的记录,我循环访问并写入文件。

我现在想将所有记录设置为固定大小,以便稍后在反序列化中我可以一次跳过多条记录。

如何修改此代码以写入固定长度记录?

       List<SP> SortedData = Data.OrderBy(o => o.DT).ToList();
        string LastdatFileName = "";
        FileStream outBin = null;
        foreach (var d in SortedData)
        {
            string binFileName = "n" + symbol + d.DT.ToString("yyyyMMdd") + ".dat";
            if (!datFileName.Equals(LastdatFileName))
            {
                if (outBin != null)
                {
                    outBin.Close();
                }
                outBin = File.Create(dbDirectory + @"'" + binFileName, 2048, FileOptions.None);
                LastdatFileName = datFileName;
            }
            Serializer.SerializeWithLengthPrefix(outBin, d.ToTickRecord(),PrefixStyle.Base128);
        }
        outBin.Close();

记录

  [ProtoContract]
    public class TickRecord
    {
        [ProtoMember(1)]
        public DateTime DT;
        [ProtoMember(2)]
        public double BidPrice;
        [ProtoMember(3)]
        public double AskPrice;
        [ProtoMember(4)]
        public int BidSize;
        [ProtoMember(5)]
        public int AskSize;
        public TickRecord(DateTime DT, double BidPrice, double AskPrice, int BidSize, int AskSize)
        {
            this.DT = DT;
            this.BidPrice = BidPrice;
            this.AskPrice = AskPrice;
            this.BidSize = BidSize;
            this.AskSize = AskSize;
        }
}

反序列化

             long skipRate = 10;

                    while ((tr = Serializer.DeserializeWithLengthPrefix<TickRecord>(fs, PrefixStyle.Base128)) != null) //fs.Length > fs.Position)
                    {
                        count++;
                        fs.Position += (38 * skipRate);
                        if (fs.Position > fs.Length)
                            break;
                        //Console.WriteLine("> " + tr.ToString());
                    }

SSCCE 为 Marc Gravell

您将需要创建 2 个按钮序列化和反序列化。

序列化创建一个虚拟数据文件。

反序列化通读它。

注释掉 fs。定位行以查看整个文件的原始读取。在我的机器上需要 12 秒。然后取消注释它,文件每次将跳过 10 条记录。希望速度提高 10 倍,但在我的机器上需要 8 秒。所以我假设改变 fs。位置很贵。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ProtoBuf;
using System.IO;
using System.Diagnostics;
namespace BinTest3
{

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Serialize_Click(object sender, EventArgs e)
        {
            FileStream outBin = null;
            string binFileName = @"C:'binfile.dft";
            outBin = File.Create(binFileName, 2048, FileOptions.None);
            DateTime d = DateTime.Now;
            TickRecord tr = new TickRecord(d, 1.02, 1.03,200,300);
            for (int i =0; i < 20000000; i++)
            {
                tr.BidPrice += 1;
                Serializer.SerializeWithLengthPrefix(outBin, tr, PrefixStyle.Base128);
            }
            outBin.Close();
            label1.Text = "Done ";
        }
        private void Deserialize_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            FileStream fs;
            string binFileName = @"C:'binfile.dft";
            fs = new FileStream(binFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4 * 4096);
            long skipRate =10;
            int count = 0;
            TickRecord tr;
            long skip = (38*skipRate);
            try
            {
                while ((tr = Serializer.DeserializeWithLengthPrefix<TickRecord>(fs, PrefixStyle.Base128)) != null) //fs.Length > fs.Position)
                {
                    count++;
                    fs.Position += skip;  //Comment out this line to see raw speed
                }
            }
            catch (Exception)
            {
            }
            fs.Close();
            sw.Stop();
            label1.Text = "Time taken: " + sw.Elapsed + " Count: " + count.ToString("n0");
        }
    }

    [ProtoContract]
    public class TickRecord
    {
        [ProtoMember(1, DataFormat = DataFormat.FixedSize)]
        public DateTime DT;
        [ProtoMember(2)]
        public double BidPrice;
        [ProtoMember(3)]
        public double AskPrice;
        [ProtoMember(4, DataFormat = DataFormat.FixedSize)]
        public int BidSize;
        [ProtoMember(5, DataFormat = DataFormat.FixedSize)]
        public int AskSize;
        public TickRecord()
        {
        }
        public TickRecord(DateTime DT, double BidPrice, double AskPrice, int BidSize, int AskSize)
        {
            this.DT = DT;
            this.BidPrice = BidPrice;
            this.AskPrice = AskPrice;
            this.BidSize = BidSize;
            this.AskSize = AskSize;
        }

    }
}

如何在Protbuf-net中写入固定长度的记录

快速浏览文档后,我认为您想要以下内容:

[ProtoMember(1, DataFormat = DataFormat.FixedSize)]
public DateTime DT;
[ProtoMember(2,)]
public double BidPrice;
[ProtoMember(3)]
public double AskPrice;
[ProtoMember(4, DataFormat = DataFormat.FixedSize)]
public int BidSize;
[ProtoMember(5, DataFormat = DataFormat.FixedSize)]
public int AskSize;

这对于数值应该没问题 - 我不确定 DataFormat 属性是否适用于DateTime字段。另一种方法是使用FixedSize数据格式序列化long Ticks,然后是转换为/从DateTime转换的属性。不过,查看代码,我认为上面写的没问题。无需为double指定数据格式,因为无论如何,它始终以固定大小的值写入。