序列化 - 反序列化(二进制)

4
我正在创建一个浏览器。第一次进入目录时,我会处理文件并提取图像,将数据序列化为一个数据文件。然后我会将这个新创建的文件反序列化到表单中进行查看。第二次进入目录时,系统会尝试反序列化该文件以填充表单。如果需要创建文件,系统可以很好地工作,但如果文件已经存在,则会收到未引用对象错误。我错过了什么?
 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循环中被注释为“problem”的一行。

堆栈跟踪...

在 Substance_Browser_12.Form1.DeserializeData(String binPath) 中, X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Form1.cs 的第151行 在 Substance_Browser_12.Form1.treeView1_NodeMouseClick(Object sender, TreeNodeMouseClickEventArgs e) 中, X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Form1.cs 的第133行 在 System.Windows.Forms.TreeView.WmNotify(Message& m) 在 System.Windows.Forms.TreeView.WndProc(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) 在 System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam) 在 System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m) 在 System.Windows.Forms.Control.WmNotify(Message& m) 在 System.Windows.Forms.Control.WndProc(Message& m) 在 System.Windows.Forms.ScrollableControl.WndProc(Message& 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(Message& m) 在 System.Windows.Forms.Control.DefWndProc(Message& m) 在 System.Windows.Forms.TreeView.WmMouseDown(Message& m, MouseButtons button, Int32 clicks) 在 System.Windows.Forms.TreeView.WndProc(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 在 System.Windows.Forms.Application.Run(Form mainForm) 在 Substance_Browser_12.Program.Main() 中, X:\Visual Studio 2010\Projects\Substance Designer\Substance_Browser_12\Substance_Browser_12\Program.cs 的第18行 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.ThreadHelper.ThreadStart()


1
你在哪一行遇到了未引用对象错误? - crthompson
你能提供错误信息和堆栈跟踪吗? - Grundy
感谢您添加实际的异常文本。"Object reference not set to instance of an object"并不意味着与"unreferenced object error"相同,这是具有误导性的。 - groverboy
4个回答

0

你只需要改成这样

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

0

我需要在DeserializeData(string binPath)中重新初始化viewerData。如果它来自UpdateDirectory(),那么它已经被初始化过了。

viewerData = new ViewerData[length];

感谢大家的贡献!


0

在 MSDN 中 BinaryFormatter.Deserialize Method (Stream)

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

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


0

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

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

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

然后反序列化对象时执行相反操作。


我原本以为数组是容器。请注意,当我最初创建数据文件然后反序列化它时,它可以正常工作。而且在这两种情况下,我都调用了完全相同的DeserializeData方法。 - topofsteel
@topofsteel - 不,你正在序列化ViewerData对象和一个整数,而不是它们的数组。顺便说一句,感谢您发布您的答案,很有趣知道BinaryFormatter是如何工作的,即反序列化仅影响流中的下一个对象(int,ViewerData)。但是这是未记录的行为,我不建议依赖它。 - groverboy
更多关于这种未记录的行为,请参见尝试同时反序列化多个对象反序列化特定对象 - groverboy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接