反序列化抛出异常

时间:2018-05-30 06:47:21

标签: c# .net

我试图将List作为BLOB存储在sqlite数据库中,但是我在重建List时遇到了一些麻烦。我承认我对BinaryFormatter或MemoryStream的工作原理不太了解。

插入一行似乎工作正常:

public void InsertRow()
{
    List<float> myList = new List<float>();
    myList.Add(12);
    myList.Add(13);
    myList.Add(14);
    myList.Add(15);
    myList.Add(16);

    var binFormatter = new BinaryFormatter();
    var mStream = new MemoryStream();
    binFormatter.Serialize(mStream, myList);

    SQLiteCommand command = new SQLiteCommand(m_dbConnection);

    byte[] data = mStream.ToArray();

    command.CommandText = "insert into photos (photo) values (@photo)";
    command.Parameters.Add("@photo", DbType.Binary, 237).Value = data;
    command.ExecuteNonQuery();
}

Deserialize方法抛出System.Runtime.Serialization.SerializationException:解析完成之前遇到的End of Stream:

public void GetRow()
{
    string sql = "select photo from photos where id = 1";
    SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);

    using (var reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            byte[] buffer = GetBytes(reader);

            var mStream = new MemoryStream();
            var binFormatter = new BinaryFormatter();

            mStream.Write(buffer, 0, 237);
            mStream.Position = 0;

            var myObject = binFormatter.Deserialize(mStream) as List<float>;
        }
    }
}

我在这里做错了什么?另外,为什么myList中的5个浮点数在序列化时会产生237个字节?

编辑:添加了GetBytes功能:

static byte[] GetBytes(SQLiteDataReader reader)
{
    const int CHUNK_SIZE = 2 * 1024;
    byte[] buffer = new byte[CHUNK_SIZE];
    long bytesRead;
    long fieldOffset = 0;
    using (MemoryStream stream = new MemoryStream())
    {
        while ((bytesRead = reader.GetBytes(0, fieldOffset, buffer, 0, buffer.Length)) > 0)
        {
            stream.Write(buffer, 0, (int)bytesRead);
            fieldOffset += bytesRead;
        }
        return stream.ToArray();
    }
}

2 个答案:

答案 0 :(得分:5)

您已经对序列化数据的大小进行了硬编码。 不要那样做!

List<float> myList = new List<float>();
myList.Add(12);
myList.Add(13);
myList.Add(14);
myList.Add(15);
myList.Add(16);

var binFormatter = new BinaryFormatter();
var mStream = new MemoryStream();
binFormatter.Serialize(mStream, myList);
Console.WriteLine(mStream.Length);

这输出238,而不是237.你丢失了一个字节,这就是为什么你在解析完成之前遇到“End of Stream”。

所以不要硬编码大小,使用流的所有字节。这也适用于反序列化。并且没有,这并不意味着你应该使用238,硬编码预期的大小是100%错误

此代码有效:

List<float> myList = new List<float>();
myList.Add(12);
myList.Add(13);
myList.Add(14);
myList.Add(15);
myList.Add(16);

var formatter = new BinaryFormatter();
var stream1 = new MemoryStream();
formatter.Serialize(stream1, myList);

var array = stream1.ToArray();
Console.WriteLine(array.Length);

var stream2 = new MemoryStream();
stream2.Write(array, 0, array.Length);
stream2.Position = 0;

foreach (var value in formatter.Deserialize(stream2) as List<float>)
    Console.WriteLine(value);

和输出:

238
12
13
14
15
16

请注意,您可以在现有字节数组周围构造MemoryStream,然后您不必重新定位它,以便上面示例中的反序列化可以缩短为:

var stream2 = new MemoryStream(array);

foreach (var value in formatter.Deserialize(stream2) as List<float>)
    Console.WriteLine(value);

答案 1 :(得分:-1)

binFormatter.Serialize(mStream, myList);

mStream.Close();  // to be sure
byte[] data = mStream.ToArray();

command.Parameters.Add("@photo", DbType.Binary).Value = data;  // don't specify (override) the size.