【问题标题】:Serialize - Deserialize (binary)序列化 - 反序列化(二进制)
【发布时间】:2014-01-04 17:58:39
【问题描述】:

我正在创建一个查看器。第一次进入目录时,通过处理文件、提取图像并将数据序列化为数据文件来创建数据文件。然后我将新创建的文件反序列化为要查看的表单。第二次进入目录时,它会看到该文件 ans 尝试反序列化它以填充表单。系统必须先创建它时工​​作正常,但如果它已经存在,我会收到未引用的对象错误。我错过了什么?

 private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            listView1.Items.Clear();
            fileInfoList.Clear();
            //fileNameList.Clear();
            ClearFlowPanel();

            TreeNode newSelected = e.Node;
            DirectoryInfo nodeDirInfo = (DirectoryInfo)newSelected.Tag;

            dirPath = nodeDirInfo.FullName;
            label_selectedPath.Text = dirPath;

            foreach (FileInfo file in nodeDirInfo.GetFiles("*.sbs", option))
            {
                if (file.Extension == ".sbs")
                {
                    fileInfoList.Add(file);

                }
            }

            foreach (FileInfo info in fileInfoList)
            {
                ListViewItem i = listView1.Items.Add(info.Name, 1);
                i.SubItems.Add(SizeInKB(info.Length));
                i.SubItems.Add(info.LastWriteTime.ToShortDateString());
            }
            listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

            string binData = dirPath + "\\" + ".browser" + "\\" + "_browser.bin";
            if (File.Exists(binData))
            {
                DeserializeData(binData); //creates error
            }
        }

        private void DeserializeData(string binPath)
        {
            FileStream fs = new FileStream(binPath, FileMode.Open);
            BinaryFormatter bin = new BinaryFormatter();

            int length = (int)bin.Deserialize(fs);

            MessageBox.Show(length.ToString());

            for (int i = 0; i < length; i++)
            {
                viewerData[i] = (ViewerData)bin.Deserialize(fs); //problem
            }

            for (int i = 0; i < viewerData.Length; i++)
            {
                PopulateFlowControl(viewerData[i]);
                viewerNameList.Add(viewerData[i].name);
            }
        }

        private void UpdateDirectory()
        {
            thumbPath = dirPath + "\\" + ".browser";
            if (!Directory.Exists(thumbPath))
            {
                Directory.CreateDirectory(thumbPath);
            }

            fileInfoArray = fileInfoList.ToArray();
            viewerData = new ViewerData[fileInfoArray.Length];

            string binData = thumbPath + "\\" + "_browser.bin";
            Stream stream = File.Open(binData, FileMode.Create);
            BinaryFormatter bin = new BinaryFormatter();
            bin.Serialize(stream, fileInfoArray.Length);

            ProgressBar_Form progressBar = new ProgressBar_Form(fileInfoArray.Length);
            progressBar.Show();

            for (int i = 0; i < fileInfoArray.Length; i++)
            {
                viewerData[i] = new ViewerData(fileInfoArray[i]);
                bin.Serialize(stream, viewerData[i]);

                progressBar.progressBar1.PerformStep();
                progressBar.label_progress.Text = "Processing : " + fileInfoArray[i].Name;

                viewerData[i].image.Dispose();

                if (File.Exists(viewerData[i].imagePath))
                {
                    File.Delete(viewerData[i].imagePath);
                }
            }

            stream.Close();
            progressBar.Close();

            DeserializeData(binData); //works fine
        }

编辑:

错误:对象引用未设置为对象的实例 - 在 DeserializeData(string binPath) 中的第一个 for 循环中注释为“问题”的行;

堆栈跟踪...

在 X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Form1.cs:line 151 中的 Substance_Browser_12.Form1.DeserializeData(String binPath) 在 X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Form1.cs:line 133 中的 Substance_Browser_12.Form1.treeView1_NodeMouseClick(Object sender, TreeNodeMouseClickEventArgs e) 在 System.Windows.Forms.TreeView.OnNodeMouseClick(TreeNodeMouseClickEventArgs e) 在 System.Windows.Forms.TreeView.WmNotify(消息& m) 在 System.Windows.Forms.TreeView.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd,Int32 味精,IntPtr wParam,IntPtr lParam) 在 System.Windows.Forms.Control.SendMessage(Int32 消息,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd,消息& m) 在 System.Windows.Forms.Control.WmNotify(消息& m) 在 System.Windows.Forms.Control.WndProc(消息和 m) 在 System.Windows.Forms.ScrollableControl.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,IntPtr hWnd,Int32 msg,IntPtr wParam,IntPtr lParam) 在 System.Windows.Forms.NativeWindow.DefWndProc(消息和 m) 在 System.Windows.Forms.Control.DefWndProc(消息和 m) 在 System.Windows.Forms.TreeView.WmMouseDown(消息和 m,MouseButtons 按钮,Int32 点击) 在 System.Windows.Forms.TreeView.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 原因,Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.Run(窗体 mainForm) 在 X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Program.cs:line 18 中的 Substance_Browser_12.Program.Main() 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数) 在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ThreadHelper.ThreadStart()

【问题讨论】:

  • 在哪一行得到未引用对象错误?
  • 你能提供错误信息和堆栈跟踪吗?
  • 感谢您添加实际的异常文本。 “对象引用未设置为对象的实例”与“未引用对象错误”的含义不同,这是一种误导。

标签: c# serialization deserialization


【解决方案1】:

在 msdn BinaryFormatter.Deserialize Method (Stream)

为了成功反序列化,流中的当前位置必须在对象图的开头。

因此,当您尝试反序列化流中的当前位置时,可能不会在对象图的开头。

【讨论】:

    【解决方案2】:

    你只需要改成这个

    private void DeserializeData(string binPath)
        {
            FileStream fs = new FileStream(binPath, FileMode.Open);
    
           fs.Seek(0, SeekOrigin.Begin);
    
            BinaryFormatter bin = new BinaryFormatter();
    
            int length = (int)bin.Deserialize(fs);
    
            MessageBox.Show(length.ToString());
    
            for (int i = 0; i < length; i++)
            {
                viewerData[i] = (ViewerData)bin.Deserialize(fs); //problem
            }
    
            for (int i = 0; i < viewerData.Length; i++)
            {
                PopulateFlowControl(viewerData[i]);
                viewerNameList.Add(viewerData[i].name);
            }
        }
    

    public static System.IO.MemoryStream Serialize(object _Object)
    {
        System.IO.MemoryStream _Return = new System.IO.MemoryStream();
        Serialize(ref _Return, _Object);
        return _Return;
    }
    
    public static void Serialize(ref System.IO.Stream Stream, object _Object)
    {
        BinaryFormatter BF = new BinaryFormatter();
        BF.Serialize(Stream, _Object);
    }
    
    public static objType Deserialize<objType>(ref System.IO.Stream Stream)
    {
        object _Return = null;
        Stream.Seek(0, SeekOrigin.Begin);
        BinaryFormatter BF = new BinaryFormatter();
        _Return = BF.Deserialize(Stream);
        return (objType)_Return;
    }
    

    【讨论】:

      【解决方案3】:

      您将多个 ViewerData 对象序列化到一个文件中,但文件中没有这些对象的容器。我不认为BinaryFormatter 支持这种用法。序列化这些对象的替代方法:

      • 为每个文件序列化一个 ViewerData。
      • 将所有 ViewerData 对象添加到一个集合中,然后序列化该集合。如果有很多大图像,使用这种方法可能会出现内存不足错误。
      • 开发一种将BinaryFormatter 与手动写入/读取相结合的算法,以避免使用过多的内存。这可能需要一个中间流,例如MemoryStream 用于序列化每个 ViewerData。请参阅下面的伪代码步骤。

      将对象计数写入文件流。
      对于每个对象。 使用 BinaryFormatter 对 MemoryStream 进行序列化。 将 MemoryStream 的长度写入文件流。 将 MemoryStream 写入文件流

      然后反序列化对象。

      【讨论】:

      • 我的印象是数组就是容器。请注意,当我最初创建数据文件然后反序列化它时,它工作正常。而且我在这两种情况下都调用了完全相同的 DeserializeData 方法。
      • @topofsteel - 不,您正在序列化 ViewerData 对象和一个整数,而不是它们的数组。顺便说一句,感谢您发布您的答案,有趣的是知道 BinaryFormatter 像这样工作,即反序列化仅影响流中的下一个对象(int,ViewerData)。然而,这是我不推荐依赖的无证行为。
      • Trying to deserialize more than 1 object at the same timeDeserialize Particular Object 了解更多关于这种无证行为的信息。
      【解决方案4】:

      我需要在 DeserializeData(string binPath) 中重新初始化 viewerData。如果它来自 UpdateDirectory() 它已经是。

      viewerData = new ViewerData[length];
      

      感谢大家的意见!

      【讨论】:

        猜你喜欢
        • 2016-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 2010-11-08
        • 1970-01-01
        • 2021-12-03
        • 2016-09-15
        相关资源
        最近更新 更多