输入流不是有效的二进制格式。起始内容

时间:2014-02-15 03:36:46

标签: c# deserialization

我之前看过这类问题,但不确定问题的根本原因是什么或如何解决。

我正在修改现有的类,以便能够将数据加载到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);
        }
    }
}

请注意,我还尝试了将Convert字节数组转换为对象函数(我在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;
}

显然我遗漏了一些重要信息。

序列化发生在与反序列化不同的应用程序中。序列化使用位转换器获取数据,转换为字节数组并将其上载到闪存。让我解释。正在序列化/反序列化的数据&amp;存储在闪存中的是校准数据。通过生产,在工厂使用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)。正确的做法是对序列化/反序列化使用相同的格式化程序 - 我将以这种方式实现它并指出是否有所作为。

1 个答案:

答案 0 :(得分:4)

更新后,显而易见的问题是您使用不同的格式化程序进行序列化和反序列化。

BinaryFormatter序列化的不仅仅是字段数据。它还序列化了类型信息和元数据,因此它知道如何反序列化对象,因此它不仅仅需要原始数据字节作为输入。

也可以在序列化端使用BinaryFormatter,或者在接收端使用手动反序列化技术。