调试System.IO.FileNotFoundException-原因和修复

今天,我想帮跟踪并修复一个非常常见且非常著名的异常:System.IO.FileNotFoundException。承认!在所有情况下,此错误都是由于尝试访问不存在的文件所致。但是,实际上有多种情况可以触发此异常。你可能认为你知道关于这个例外的一切,但我打赌你还有一些东西要学。至少我在深入了解这篇文章的细节时做到了。请继续关注以了解全部情况。

文件类型未找到错误

让我们来探究这个错误的不同原因。FileNotFoundException上的Message属性提供了有关发生情况的提示。

找不到文件“filename”

如消息所述,您正在尝试加载找不到的文件。可以使用一行代码复现此类错误:

try
{
    File.ReadAllText("non-existing.file");
}
catch (FileNotFoundException e)
{
    Console.WriteLine(e.ToString());
}

第三行是这里最重要的一条。我正在尝试加载文件系统中不存在的文件(non existing.file)。在上面的示例中,程序将输出打印到控制台,如下所示:

System.IO.FileNotFoundException: Could not find file 'APP_PATH\bin\Debug\non-existing.file'.
File name: 'APP_PATH\bin\Debug\non-existing.file'
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost)
   at System.IO.File.InternalReadAllText(String path, Encoding encoding, Boolean checkHost)
   at System.IO.File.ReadAllText(String path)
   at ConsoleApp.Program.Main(String[] args) in APP_PATH\Program.cs:line 19

APP_PATH将是找不到的文件的绝对路径。这种类型的FileNotFoundException实际上包含调试问题所需的所有信息。异常消息包含一个很好的错误描述,以及丢失文件的绝对路径。如果要向用户显示路径,或者在找不到文件时创建该文件,则FileNotFoundException上有一个nifty属性可用:

catch (FileNotFoundException e)
{
    File.Create(e.FileName);
}

在本例中,我只是使用Filename属性创建丢失的文件。我已经看到代码解析异常消息以获取丢失文件的名称,当绝对路径在异常上可用时,这有点让人失望。

系统找不到指定的文件。(HRESULT的异常:0x80070002)

此错误通常在尝试加载不存在的程序集时引发。可以这样复现错误:

try
{
    Assembly.LoadFile("c:\\Nonexisting.dll");
}
catch (FileNotFoundException e)
{
    Console.WriteLine(e.ToString());
}

在这种情况下,程序仍然抛出一个FileNotFoundException。但异常消息不同:

System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
   at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)
   at System.Reflection.Assembly.LoadFile(String path)
   at ConsoleApp.Program.Main(String[] args) in APP_PATH\Program.cs:line 20

与读取丢失文件时引发的错误不同,来自System.Reflection命名空间的消息更难理解。若要查找此错误的原因,您需要查看堆栈跟踪,该跟踪提示这是在Assembly.LoadFile期间发生的。注意,异常消息中不存在文件名,在本例中,FileNotFoundException上的filename属性为空。

无法加载文件或程序集“assembly”或其依赖项之一。系统找不到指定的文件。

与上述错误类似的错误是无法加载文件或程序集“assembly”或其依赖项之一。系统找不到指定的文件。错误。这也意味着程序正在尝试加载找不到的程序集。可以通过创建使用其他程序集的程序来重新创建错误。生成程序,从bin\Debug文件夹中删除引用程序集(.dll文件),然后运行程序。在这种情况下,程序在启动时失败:

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at ConsoleApp.Program.Main(String[] args)

在本例中,我引用了一个名为Lib的程序集,它不存在于磁盘或全局程序集缓存(GAC)中。此错误的典型原因是引用的程序集不在文件系统上。这可能有多种原因。为了帮助您调试,需要检查以下几点:

  • 如果要使用Azure DevOps或Octopus Deploy等系统进行部署,请确保将生成输出中的所有文件复制到目标。
  • 在Visual Studio中的引用程序集上单击鼠标右键,单击“属性”,并确保“复制本地”设置为true:

 

 

在IIS上运行时出现访问错误

到目前为止,此错误的所有实例都是磁盘中丢失的文件。我想用一个关于安全的简短评论来结束这篇文章。在某些情况下,FileNotFoundException可能是由试图访问文件的用户帐户引起的,只是没有必要的访问权限。在最佳情况下,发生这种情况时,框架应抛出System.UnauthorizedAccessException。但我在过去看到过在IIS上托管网站的问题。请确保ASP.NET工作进程帐户(或网络服务,具体取决于您使用的用户)可以访问运行应用程序所需的所有文件和文件夹。

要确保应用程序池用户具有访问权限,请执行以下操作:

  • 右键单击包含web应用程序的文件夹
  • 单击属性
  • 选择“安全”选项卡
  • 单击编辑。。。
  • 单击添加。。。
  • 在文本区域中输入IIS AppPool\DefaultAppPool
  • 单击“检查名称”并验证是否已解析用户
  • 单击“确定”
  • 将完全控制权分配给新用户并保存

posted on 2020-04-03 08:26  活着的虫子  阅读(49563)  评论(0编辑  收藏  举报

导航