Reputation: 7005
What might be causing this error?
Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see http://stackoverflow.com/q/2152978/23354
I followed the help link above, but setting FileMode.Truncate has not helped...
The issue always happen at same position in one particular file being deserialized. I have recreated the file several times.
[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(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;
}
public TickRecord()
{
}
}
EDIT FOR JON SKEET
This works. But my problem arises when I use my real data (which I cannot share). Most file I deserialize work fine, but one does not....
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";
byte[] data = File.ReadAllBytes(binFileName);
MemoryStream ms = new MemoryStream(data);
long skipRate =10;
int count = 0;
TickRecord tr;
long skip = (38*skipRate);
try
{
while ((tr = Serializer.DeserializeWithLengthPrefix<TickRecord>(ms, PrefixStyle.Base128)) != null) //fs.Length > fs.Position)
{
count++;
ms.Seek(skip, SeekOrigin.Current);
}
}
catch (Exception)
{
}
ms.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;
}
}
}
EDIT 2 PROBLEM IS IN Serialize - it is NOT fixedsize as I had thought:
private void Once_Click(object sender, EventArgs e)
{
FileStream outBin = null;
string binFileName = @"C:\binfile.dft";
outBin = File.Create(binFileName, 2048, FileOptions.None);
DateTime d = DateTime.Now;
long lastPosition = 0;
TickRecord tr = new TickRecord(d, 1.02, 1.03, 200, 300);
Serializer.SerializeWithLengthPrefix(outBin, tr, PrefixStyle.Base128);
Console.WriteLine("outBin.Position: " + outBin.Position + " lastPosition: " + lastPosition + " diff: " + (outBin.Position-lastPosition));
lastPosition = outBin.Position;
tr = new TickRecord(d, 1.02, 0.0, 200, 300);
Serializer.SerializeWithLengthPrefix(outBin, tr, PrefixStyle.Base128);
Console.WriteLine("outBin.Position: " + outBin.Position + " lastPosition: " + lastPosition + " diff: " + (outBin.Position - lastPosition));
outBin.Close();
label1.Text = "Done ";
}
[ProtoContract]
public class TickRecord
{
[ProtoMember(1, DataFormat = DataFormat.FixedSize)]
public DateTime DT;
[ProtoMember(2, DataFormat = DataFormat.FixedSize)]
public double BidPrice;
[ProtoMember(3, DataFormat = DataFormat.FixedSize)]
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;
}
}
This gives:
outBin.Position: 38 lastPosition: 0 diff: 38
outBin.Position: 67 lastPosition: 38 diff: 29
So it appears that the size of the variable is different when it is ZERO.
How can I make a ZERO double get same size as a non-zero double?
Upvotes: 2
Views: 10259
Reputation: 7005
You need IsRequired attribute.
ZERO-valued double and int fields are serialized differently to non-zero fields. So although I specified FixedSize - it was not.
The following creates a really FixedSize record:
[ProtoContract]
public class TickRecord
{
[ProtoMember(1, DataFormat = DataFormat.FixedSize, IsRequired = true)]
public DateTime DT;
[ProtoMember(2, DataFormat = DataFormat.FixedSize, IsRequired = true)]
public double BidPrice;
[ProtoMember(3, DataFormat = DataFormat.FixedSize, IsRequired = true)]
public double AskPrice;
[ProtoMember(4, DataFormat = DataFormat.FixedSize, IsRequired = true)]
public int BidSize;
[ProtoMember(5, DataFormat = DataFormat.FixedSize, IsRequired = true)]
public int AskSize;
Upvotes: 3