【问题标题】:The input stream is not a valid binary format. The starting contents输入流不是有效的二进制格式。起始内容
【发布时间】: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


【解决方案1】:

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

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

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

【讨论】:

  • 我遇到了同样的问题,我通过使用 BinaryFormatter 序列化(保存)并使用 BinaryFormatter 再次读取来解决它。
  • 怎么做“手动反序列化技术”,我要反序列化成PSCustomObject
  • @Ranvir 这取决于您如何进行序列化。在问题中,OP 使用某些值的原始字节进行序列化,这些值是使用BitConveter 获得的。
  • 我在序列化和反序列化中都使用 BinaryFormatter 并收到此错误
猜你喜欢
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
相关资源
最近更新 更多