【发布时间】:2014-02-15 03:36:46
【问题描述】:
我之前看到过这类问题,但不确定问题的根本原因是什么或如何解决。
我正在修改一个现有的类,以便能够将数据从 Flash 加载到成员变量中。现在,该类通过 load 函数从文件中加载数据。此函数已被重载以接收字节数组。
从闪存读回的数据放入这个字节数组中。
抛出的错误是(发生在... = formatter.Deserialize(stream) 行):
输入流不是有效的二进制格式。起始内容(以字节为单位)为:93-E3-E6-3F-C3-F5-E4-41-00-C0-8D-C3-14-EE-4A-C3-00 ...
这里有趣的是内容正是被传递到流中的字节数组的内容。换句话说,这是来自闪存的数据,这正是我想要序列化的。我不确定为什么会抛出错误。
或者更好的问题是BinaryFormatter 的有效二进制格式是什么?它需要一定的尺寸吗?是否需要特定的最终价值?某些值无效吗?字节数组输入的当前大小为 24 字节。
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.IO;
using Galileo.Data;
using System.Xml.Serialization;
using System.Reflection;
using System.Runtime.InteropServices;
using UComm;
using System.Runtime.Serialization.Formatters.Binary;
using ULog;
public void Load(byte[] spCalfromPrimary)
{
try
{
Type settingsType = this.GetType();
object tmp = Activator.CreateInstance(settingsType);
Stream stream = new MemoryStream();
stream.Write(spCalfromPrimary, 0, spCalfromPrimary.Length);
stream.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
//tmp = formatter.Deserialize(stream);
formatter.Deserialize(stream); //**<--- throws error here**
// Use reflection to copy all public properties from the temporary object into this one.
PropertyInfo[] properties = settingsType.GetProperties();
foreach (PropertyInfo property in properties)
{
object value = property.GetValue(tmp, null);
if (value == null)
{
throw new FileFormatException("Null value encountered in settings file");
}
else
{
property.SetValue(this, value, null);
}
}
}
catch (Exception ex)
{
_logger.DebugException("Failed to load spatial cal value from FW", ex);
Console.WriteLine(ex.Message);
}
}
// <summary>
/// Loads the setting from file
/// </summary>
public void Load()
{
Type settingsType = this.GetType();
XmlSerializer xser = new XmlSerializer(settingsType);
object tmp = Activator.CreateInstance(settingsType);
using (StreamReader reader = new StreamReader(_filename)) { tmp = xser.Deserialize(reader); }
// Use reflection to copy all public properties from the temporary object into this one.
PropertyInfo[] properties = settingsType.GetProperties();
foreach (PropertyInfo property in properties)
{
object value = property.GetValue(tmp, null);
if (value == null)
{
throw new FileFormatException("Null value encountered in settings file");
}
else
{
property.SetValue(this, value, null);
}
}
}
请注意,我还尝试了将字节数组转换为对象函数(我在 stackoverflow 上找到)。当我使用这个函数时,仍然在.Deserialize(memStream) 处抛出异常。
// Convert a byte array to an Object
private Object ByteArrayToObject(byte[] arrBytes)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object) binForm.Deserialize(memStream);
return obj;
}
显然我遗漏了一些重要信息。
序列化发生在与反序列化不同的应用程序中。序列化使用位转换器获取数据,转换为字节数组并将其上传到闪存。让我解释。正在序列化/反序列化和存储在闪存中的数据是校准数据。校准在工厂使用 Application1 由生产执行。这使用位转换器将每个字段放入流中,然后序列化流。
CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.ScaleTrackingDMD);
CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.RotationAngle);
CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.CenterOfRotation.dx);
其中函数 FloatToStream 定义为:
public static void FloatToStream(byte[] buf, ref int index, float val)
{
Buffer.BlockCopy(BitConverter.GetBytes(val), 0, buf, index, sizeof(float));
index += sizeof(float);
}
因此,构成校准的每个字段都以这种方式放入流中。将数据放入流中并构造一个字节数组并将其发送到闪存。
另一方面,一旦产品出厂并投入使用,Application2(用户应用程序)就有一个包含所有校准字段的校准对象。这会读取闪存,并获取 Application1 写入的数据。 Application2 正在尝试使用 BinaryFormatter 和上面的代码反序列化校准数据。我得出的结论是这是不可能的(感谢Rotem)。正确的做法是对序列化/反序列化使用相同的格式化程序 - 我将以这种方式实现它并指出这是否会产生影响。
【问题讨论】:
-
什么是序列化流?
BinaryFormatter只能反序列化使用BinaryFormatter序列化的数据。
标签: c# deserialization