【问题标题】:Why is this producing an "Empty Path Name Is Not Legal" exception?为什么这会产生“空路径名不合法”异常?
【发布时间】:2014-03-31 16:58:22
【问题描述】:

我正在尝试使用 BinaryFormatter 来序列化我正在开发的程序的状态,但是当我尝试反序列化生成的文件时出现以下错误。我的代码检查以确保文件名有效(在这里看到很多类似的问题后已经添加了),所以我不明白这个错误是如何发生的:

System.ArgumentException
Message=空路径名不合法。
来源=mscorlib
堆栈跟踪:
在 System.IO.FileStream.Init(字符串路径、FileMode 模式、FileAccess 访问、Int32 权限、Boolean useRights、FileShare 共享、Int32 bufferSize、FileOptions 选项、SECURITY_ATTRIBUTES secAttrs、String msgPath、Boolean bFromProxy、Boolean useLongPath)
在 System.IO.FileStream..ctor(字符串路径、FileMode 模式、FileAccess 访问、FileShare 共享)
在 System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri、Stream 流、BitmapCacheOption cacheOption、Guid& clsId、Boolean& isOriginalWritable、Stream& uriStream、UnmanagedMemoryStream& unmanagedMemoryStream、SafeFileHandle& safeFilehandle)
在 System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri,Uri uri,流流,BitmapCreateOptions createOptions,BitmapCacheOption cacheOption,RequestCachePolicy uriCachePolicy,布尔 insertInDecoderCache)
在 System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
在 System.Windows.Media.Imaging.BitmapImage.EndInit()
在 StarShips.Ship..ctor(SerializationInfo info, StreamingContext ctxt) 在 C:\Projects\Dalek\StarShips\Ship.cs:387 行

这是我最初创建文件的 Save 方法:

Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
sfd.FileName = "NewGame";
sfd.DefaultExt = ".sav";
sfd.Filter = "Save Games (.sav)|*.sav";
Nullable<bool> result = sfd.ShowDialog();
if (result == true)
{
    string fileName = sfd.FileName;
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
    GameTest t = new GameTest();
    t.Players = GameState.Players;
    formatter.Serialize(stream, t);

    MessageBox.Show(string.Format("Save Complete! Size: {0}",stream.Length));
    stream.Close();
}

这是引发异常的代码:

Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
ofd.FileName = "NewGame";
ofd.DefaultExt = ".sav";
ofd.Filter = "Save Games (.sav)|*.sav";
Nullable<bool> result = ofd.ShowDialog();
if (result == true)
{
    string fileName = ofd.FileName;
    System.Diagnostics.Debug.WriteLine(fileName);
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
    stream.Position = 0;
    MessageBox.Show(string.Format("size: {0}, Filename: {1}", stream.Length,((FileStream)stream).Name));
    GameTest t = (GameTest)formatter.Deserialize(stream); // Error occurs here
    stream.Close();
}

我已经尝试从 C 驱动器的根目录,甚至是程序的执行文件夹中,几乎在我的文件系统中的任何地方进行保存/加载。
我尝试进入反序列化,它迭代了大量的对象图,但突然回到我上面的反序列化调用并抛出异常。
反序列化之前的消息框显示流的文件名是有效的,为什么我会收到此消息?

编辑:如果我在调试时继续跳过错误,我会收到另一个错误:“在解析完成之前遇到流结束。”我仔细检查了我的所有类,并且所有 GetObjectData 方法都为序列化构造函数添加了相同的值,所以我不知道它在流之外的什么地方运行。

【问题讨论】:

  • 你有文件名,但实际路径在哪里?
  • FileName 包括完整路径,例如“C:\NewGame.sav”。据我所知,基本序列化的 MSDN 文章也是这样处理这个问题的,反序列化在抛出错误之前会通过大部分对象图。
  • 您为什么使用 Win32.OpenFileDialog 而不是 Forms.OpenFileDialog?可能返回的路径不兼容?
  • @jcyost:这是在 WPF 应用程序中,老实说,我只是按照我搜索的教程进行操作。
  • @aw04 文件名总是包含我从哪里加载文件的完整路径,所以我不确定在 OpenFileDialog 上设置 InitialDirectory 是否会影响 BinaryFormatter.Deserialize 方法。

标签: c# .net serialization


【解决方案1】:

在 StarShips.Ship..ctor(SerializationInfo info, StreamingContext ctxt)

异常的调用堆栈表明您正在寻找这个问题的完全错误的角落。您假设错误的是包含序列化数据的文件的路径,堆栈跟踪讲述了一个非常不同的故事。

以防混淆,.ctor 是类构造函数的内部 CLR 名称。所以实际上是你的 Ship 类构造函数爆炸了。它尝试使用 BitmapImage(Uri) 构造函数创建一个 BitmapImage 对象。有问题的是构造函数的参数。可能是因为您忘记序列化位图的文件名或没有正确处理此字符串为 null 或为空。

在 Ship 构造函数上放置一个断点以单步执行代码。或者使用 Debug + Exceptions,勾选 CLR 异常的 Thrown 复选框,以便调试器在抛出异常时停止。或者删除代码中吞下异常的 try/catch,它会妨碍诊断问题。

【讨论】:

  • 啊哈!我专注于顶部并错过了那部分。自我注意:下次阅读整个堆栈跟踪。
猜你喜欢
  • 1970-01-01
  • 2014-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多