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

TreeView序列化为byte[]后反序列化抛出SerializationException求助

TreeView序列化后反序列化失败的解决思路

问题描述

尝试将TreeView转换为byte数组后还原,窗体加载时可正常加载文档结构,序列化过程已实现,但反序列化byte数组还原为TreeView时抛出System.Runtime.Serialization.SerializationException异常。

错误触发代码行

_list = bf.Deserialize(ms) as List<TreeNode>;

完整代码

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        string filepath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        ListDirectory(treeView1, filepath);
    }

    private static void ListDirectory(TreeView treeView, string path)
    {
        treeView.Nodes.Clear();

        var stack = new Stack<TreeNode>();
        var rootDirectory = new DirectoryInfo(path);
        var node = new TreeNode(rootDirectory.Name) { Tag = rootDirectory };
        stack.Push(node);

        while (stack.Count > 0)
        {
            var currentNode = stack.Pop();
            var directoryInfo = (DirectoryInfo)currentNode.Tag;

            foreach (var directory in directoryInfo.GetDirectories())
            {
                var childDirectoryNode = new TreeNode(directory.Name) { Tag = directory };
                currentNode.Nodes.Add(childDirectoryNode);
                stack.Push(childDirectoryNode);
            }

            foreach (var file in directoryInfo.GetFiles())
                currentNode.Nodes.Add(new TreeNode(file.Name));
        }

        treeView.Nodes.Add(node);
    }

    private Byte[] SerilizeQueryFilters()
    {
        BinaryFormatter bf = new BinaryFormatter();

        List<TreeNode> list = new List<TreeNode>();

        foreach(TreeNode node in treeView1.Nodes)
        {
            list.Add(node);
        }

        using (MemoryStream ms = new MemoryStream())
        {
            bf.Serialize(ms, list);
            return ms.GetBuffer();
        }
    }

    private void DeSerilizeQueryFilters(byte[] items)
    {
        BinaryFormatter bf = new BinaryFormatter();

        try
        {
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(items, 0, items.Length);
                ms.Position = 0;
                _list = bf.Deserialize(ms) as List<TreeNode>;
                treeView2.Nodes.AddRange(_list.ToArray());
            }
        }
        catch(Exception e)
        { 
            Console.WriteLine(e.StackTrace);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        byte[] data = SerilizeQueryFilters();
        DeSerilizeQueryFilters(data);
    }
}

解决思路

1. 核心问题:不可序列化对象导致异常

TreeNode类本身未标记为可序列化,且你给节点Tag属性赋值的DirectoryInfo对象同样不支持二进制序列化,这是触发异常的根本原因。

2. 修复方案:自定义可序列化数据结构

不要直接序列化TreeNode,先将TreeView结构转换为自定义的可序列化类,序列化完成后,反序列化时再重新构建TreeNode。

示例自定义可序列化类:

[Serializable]
public class TreeItem
{
    public string Name { get; set; }
    public bool IsDirectory { get; set; }
    public string Path { get; set; } // 存储路径而非DirectoryInfo对象,方便反序列化重建
    public List<TreeItem> Children { get; set; } = new List<TreeItem>();
}

3. 修改序列化逻辑

将TreeView节点转换为TreeItem后再序列化:

private Byte[] SerilizeQueryFilters()
{
    BinaryFormatter bf = new BinaryFormatter();
    // 假设TreeView只有一个根节点
    var rootItem = ConvertTreeNodeToTreeItem(treeView1.Nodes[0]);
    
    using (MemoryStream ms = new MemoryStream())
    {
        bf.Serialize(ms, rootItem);
        return ms.ToArray(); // 用ToArray()替代GetBuffer(),避免返回未使用的空字节
    }
}

private TreeItem ConvertTreeNodeToTreeItem(TreeNode node)
{
    var item = new TreeItem
    {
        Name = node.Text,
        IsDirectory = node.Tag is DirectoryInfo
    };
    
    if (item.IsDirectory)
    {
        item.Path = ((DirectoryInfo)node.Tag).FullName;
    }
    
    foreach (TreeNode childNode in node.Nodes)
    {
        item.Children.Add(ConvertTreeNodeToTreeItem(childNode));
    }
    
    return item;
}

4. 修改反序列化逻辑

将反序列化得到的TreeItem重新构建为TreeNode:

private void DeSerilizeQueryFilters(byte[] items)
{
    BinaryFormatter bf = new BinaryFormatter();

    try
    {
        using (MemoryStream ms = new MemoryStream(items))
        {
            var rootItem = bf.Deserialize(ms) as TreeItem;
            var rootNode = ConvertTreeItemToTreeNode(rootItem);
            treeView2.Nodes.Clear();
            treeView2.Nodes.Add(rootNode);
        }
    }
    catch(Exception e)
    { 
        Console.WriteLine(e.ToString()); // 打印完整异常信息,便于排查
    }
}

private TreeNode ConvertTreeItemToTreeNode(TreeItem item)
{
    var node = new TreeNode(item.Name);
    if (item.IsDirectory)
    {
        node.Tag = new DirectoryInfo(item.Path);
    }
    
    foreach (var childItem in item.Children)
    {
        node.Nodes.Add(ConvertTreeItemToTreeNode(childItem));
    }
    
    return node;
}

5. 额外优化点

  • 用ms.ToArray()替代ms.GetBuffer():GetBuffer()返回MemoryStream的内部缓冲区,包含未使用的空字节,会增大序列化体积且可能引发反序列化异常。
  • 异常处理中打印e.ToString():相比仅打印StackTrace,能获取更完整的错误信息,快速定位问题。
  • 存储路径而非DirectoryInfo对象:避免序列化不可序列化的类型,反序列化时通过路径重建对象更可靠。

内容的提问来源于stack exchange,提问作者Poligamer YT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:35:22