结构的二进制序列化未初始化阵列
我已经提供了一个模拟该场景的最小代码。下面是代码:结构的二进制序列化未初始化阵列
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
namespace Serialization
{
class Program
{
static void Main(string[] args)
{
string[] annotates = { "1", "2"};
Guides[] g1 = new Guides[2];
g1[0].comments = (string[])annotates.Clone();
g1[1].comments = (string[])annotates.Clone();
Guides[] g2 = new Guides[2];
g2[0].comments = (string[])annotates.Clone();
g2[1].comments = (string[])annotates.Clone();//to be commented later
arrayStruct arrStr1 = new arrayStruct();
arrStr1.guides_array = g1;
arrayStruct arrStr2 = new arrayStruct();
arrStr2.guides_array = g2;
using (MoveSaver objSaver = new MoveSaver(@"C:\1.bin"))
{
MoveAndTime mv1 = new MoveAndTime();
MoveAndTime mv2 = new MoveAndTime();
mv1.MoveStruc = "1";
mv1.timeHLd = DateTime.Now;
mv1.arr = arrStr1;
objSaver.SaveToFile(mv1);
mv2.MoveStruc = "2";
mv2.timeHLd = DateTime.Now;
mv2.arr = arrStr2;
objSaver.SaveToFile(mv2);
}
using (MoveSaver svrObj = new MoveSaver())
{
List<MoveAndTime> MVTobjs = svrObj.DeSerializeObject(@"C:\1.bin");
foreach (MoveAndTime item in MVTobjs)
{
Console.WriteLine(item.arr.guides_array[0].comments[0]);
}
}
}
}
public class MoveSaver : IDisposable
{
public void Dispose()
{
if (fs != null)
{
fs.Close();
}
}
FileStream fs;
StreamWriter sw;
public string filename { get; set; }
public MoveSaver(string FileName)
{
this.filename = FileName;
fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
public MoveSaver()
{
}
~MoveSaver()
{
if (fs != null)
{
fs.Close();
}
}
public List<MoveAndTime> DeSerializeObject(string filename)
{
List<MoveAndTime> retList = new List<MoveAndTime>();
MoveAndTime objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
while (stream.Position != stream.Length)
{
objectToSerialize = (MoveAndTime)bFormatter.Deserialize(stream);
retList.Add(objectToSerialize);
}
stream.Close();
return retList;
}
public bool SaveToFile(MoveAndTime moveTime)
{
try
{
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(fs, moveTime);
return true;
}
catch (Exception)
{
return false;
}
}
}
[Serializable]
public struct MoveAndTime
{
public string MoveStruc;
public DateTime timeHLd;
public arrayStruct arr;
}
[Serializable]
public struct arrayStruct
{
public Guides[] guides_array;
}
[Serializable]
public struct Guides
{
public string[] comments;
public string name;
}
}
在这种代码的一个结构包含多个结构,其中一个包含的阵列。尝试一下代码,它编译得很好,但是在真实场景中,整个数组并没有被填充,所以会有其他数组元素未指定。要看到这种效果(在行动!)注释行g2[1].comments = (string[])annotates.Clone();
并立即尝试代码。您将在反序列化时遇到错误。我怎样才能避免它?我应该将包含该数组的结构定义为一个类并将它们全部新建(希望我正在寻找基于结构的类的解决方案)?
编辑: 我更改了结构类,并通过新的每个实例工作正常。这里是代码:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
namespace Serialization
{
class Program
{
static void Main(string[] args)
{
string[] annotates = { "1", "2"};
GuidesClass[] g1 = new GuidesClass[2];
g1[0] = new GuidesClass();
g1[0].comments = (string[])annotates.Clone();
g1[1] = new GuidesClass();
g1[1].comments = (string[])annotates.Clone();
GuidesClass[] g2 = new GuidesClass[2];
g2[0] = new GuidesClass();
g2[0].comments = (string[])annotates.Clone();
g2[1] = new GuidesClass();
//g2[1].comments = (string[])annotates.Clone();
array_cls arrStr1 = new array_cls();
arrStr1.guides_array = g1;
array_cls arrStr2 = new array_cls();
arrStr2.guides_array = g2;
using (MoveSaver objSaver = new MoveSaver(@"C:\1.bin"))
{
M_T mv1 = new M_T();
M_T mv2 = new M_T();
mv1.MoveStruc = "1";
mv1.timeHLd = DateTime.Now;
mv1.arr = arrStr1;
objSaver.SaveToFile(mv1);
mv2.MoveStruc = "2";
mv2.timeHLd = DateTime.Now;
mv2.arr = arrStr2;
objSaver.SaveToFile(mv2);
}
using (MoveSaver svrObj = new MoveSaver())
{
List<M_T> MVTobjs = svrObj.DeSerializeObject(@"C:\1.bin");
foreach (M_T item in MVTobjs)
{
Console.WriteLine(item.arr.guides_array[0].comments[0]);
}
}
}
}
public class MoveSaver : IDisposable
{
public void Dispose()
{
if (fs != null)
{
fs.Close();
}
}
FileStream fs;
StreamWriter sw;
public string filename { get; set; }
public MoveSaver(string FileName)
{
this.filename = FileName;
fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
public MoveSaver()
{
}
~MoveSaver()
{
if (fs != null)
{
fs.Close();
}
}
public List<M_T> DeSerializeObject(string filename)
{
List<M_T> retList = new List<M_T>();
M_T objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
while (stream.Position != stream.Length)
{
objectToSerialize = (M_T)bFormatter.Deserialize(stream);
retList.Add(objectToSerialize);
}
stream.Close();
return retList;
}
public bool SaveToFile(M_T moveTime)
{
try
{
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(fs, moveTime);
return true;
}
catch (Exception)
{
return false;
}
}
}
[Serializable]
public class M_T
{
public string MoveStruc;
public DateTime timeHLd;
public array_cls arr;
}
[Serializable]
public class array_cls
{
public GuidesClass[] guides_array = new GuidesClass[10];
}
[Serializable]
public class GuidesClass
{
public string[] comments;
public string name;
}
}
我已经玩了一段代码,我可以repro为结构和类;最终我怀疑这里的问题是BinaryFormatter
的设计不像这样可追加,也就是说我怀疑它是错误解释当前的下一个对象的数据。
FWIW,那些真的不应该是结构,你是(IMO)可怕地over-engineering保存/加载代码。我改变了它,以便保存方法花了List<MoveAndTime>
,并且加载代码返回了一个单个List<MoveAndTime>
(即只有一个流中最外层的对象)并且它工作正常,支持我的理论。
如果你需要能够逐渐追加单个对象,我会建议protobuf网;您可以使用SerializeWithLengthPrefix
以适合追加的方式编写对象,并使用DeserializeWithLengthPrefix
从流中读取单个对象,或者使用DeserializeItems
读取流(作为序列)中的所有项目。
例如,使用protobuf网V2(仅可作为代码的时刻):
using System;
using System.Collections.Generic;
using System.IO;
using ProtoBuf;
namespace Serialization
{
class Program
{
static void Main(string[] args)
{
string[] annotates = { "1", "2" };
Guides[] g1 = new Guides[2];
g1[0].comments = (string[])annotates.Clone();
g1[1].comments = (string[])annotates.Clone();
Guides[] g2 = new Guides[2];
g2[0].comments = (string[])annotates.Clone();
g2[1].comments = (string[])annotates.Clone();//to be commented later
arrayStruct arrStr1 = new arrayStruct();
arrStr1.guides_array = g1;
arrayStruct arrStr2 = new arrayStruct();
arrStr2.guides_array = g2;
using (Stream file = File.Create(@"1.bin"))
{
MoveAndTime mv1 = new MoveAndTime();
MoveAndTime mv2 = new MoveAndTime();
mv1.MoveStruc = "1";
mv1.timeHLd = DateTime.Now;
mv1.arr = arrStr1;
Serializer.SerializeWithLengthPrefix(file, mv1, PrefixStyle.Base128, Serializer.ListItemTag);
mv2.MoveStruc = "2";
mv2.timeHLd = DateTime.Now;
mv2.arr = arrStr2;
Serializer.SerializeWithLengthPrefix(file, mv2, PrefixStyle.Base128, Serializer.ListItemTag);
}
using (Stream file = File.OpenRead(@"1.bin"))
{
List<MoveAndTime> MVTobjs = Serializer.Deserialize<List<MoveAndTime>>(file);
foreach (MoveAndTime item in MVTobjs)
{
Console.WriteLine(item.arr.guides_array[0].comments[0]);
}
}
}
}
[ProtoContract]
public struct MoveAndTime
{
[ProtoMember(1)]
public string MoveStruc;
[ProtoMember(2)]
public DateTime timeHLd;
[ProtoMember(3)]
public arrayStruct arr;
}
[ProtoContract]
public struct arrayStruct
{
[ProtoMember(1)]
public Guides[] guides_array;
}
[ProtoContract]
public struct Guides
{
[ProtoMember(1)]
public string[] comments;
[ProtoMember(2)]
public string name;
}
}
V1(作为一个DLL,更稳定)会的工作几乎是相同的,但没有按不支持结构 - 只有类。
但强调:
- 他们应该是类
- 公共字段是一个坏主意
为工作代码,请参阅编辑部分。 – 2011-03-08 18:21:23
什么错误? – Oded 2011-03-05 08:58:32
出于好奇,**为什么**是结构?他们看起来不像典型的结构(特别是因为他们是可变的),并且没有充分的理由,他们应该默认为类。 – 2011-03-05 09:14:24
@Oded:“输入流不是有效的二进制格式”,在实际的代码中,错误与二进制头相关。尝试用注释行编译代码,您将看到错误。 – 2011-03-05 09:30:45