You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

反序列化抛出异常:SQLite存储List<float>为BLOB后无法重建问题

问题:将List作为BLOB存入SQLite后反序列化失败

我尝试将List<float>作为BLOB存储到SQLite数据库,但重建List时遇到System.Runtime.Serialization.SerializationException异常,提示“End of Stream encountered before parsing was completed”。插入数据的代码运行正常,但反序列化时出错,同时我也好奇为什么5个float序列化后会生成237字节的数据。

插入数据代码:

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(); 
}

反序列化代码(出错):

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>; 
        } 
    } 
}

补充的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(); 
    } 
}

问题分析与解决

1. 反序列化失败的核心原因

你在反序列化时犯了一个低级但致命的错误:硬编码了写入MemoryStream的字节数为237。

你的GetBytes函数已经完美完成了它的工作——从数据库中读取了完整的BLOB数据,返回的buffer是完整的序列化字节数组。但你强制只写入237字节,这会导致两种情况:

  • 如果实际存储的字节数小于237:写入的是不完整的序列化流,反序列化时自然会报“流提前结束”的错误
  • 如果实际存储的字节数大于237:同样只写入了部分数据,反序列化无法解析完整的对象结构

修正后的反序列化代码:

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); 
            // 直接用完整的字节数组初始化MemoryStream,自动定位到流的起始位置
            using (var mStream = new MemoryStream(buffer)) { 
                var binFormatter = new BinaryFormatter(); 
                var myObject = binFormatter.Deserialize(mStream) as List<float>; 
            } 
        } 
    } 
}

另外,插入数据时你也硬编码了参数长度为237,这完全没必要,SQLite会自动处理BLOB的长度,改成下面这样更灵活:

command.Parameters.Add("@photo", DbType.Binary).Value = data;

2. 为什么5个float序列化后是237字节?

BinaryFormatter的序列化逻辑远不止存储原始数据,它会携带大量元数据:

  • 目标类型的完整标识(包括命名空间、程序集版本信息)
  • List的结构元数据(比如容量、元素数量)
  • .NET序列化框架的额外标记、头信息

每个float本身是4字节,5个加起来才20字节,但加上这些元数据后,总字节数就会膨胀到237左右。如果想减少序列化后的字节体积,可以考虑更轻量的方案:

  • 手动将List<float>转换为byte[](逐个float转4字节直接拼接)
  • 使用System.Text.Json、MessagePack这类高效的序列化库

内容的提问来源于stack exchange,提问作者Q-bertsuit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:09:26