如何在执行文件io时正确处理异常

时间:2008-09-17 19:36:12

标签: c# .net file-io exception-handling

我常常发现自己会以某种方式与文件进行交互,但在编写代码之后,我总是不确定它实际上是多么糟糕。问题是我不完全确定文件相关操作如何失败,因此是处理考试的最佳方法。

简单的解决方案似乎只是捕获代码抛出的任何IOExceptions并为用户提供“无法访问的文件”错误消息,但是可以获得更细粒度的错误消息。有没有办法确定这些错误之间的差异,如文件被另一个程序锁定,以及由于硬件错误而无法读取的数据?

鉴于以下C#代码,您将如何处理用户友好(尽可能提供信息)方式的错误?

public class IO
{
   public List<string> ReadFile(string path)
   {
      FileInfo file = new FileInfo(path);

      if (!file.Exists)
      {
         throw new FileNotFoundException();
      }

      StreamReader reader = file.OpenText();
      List<string> text = new List<string>();

      while (!reader.EndOfStream)
      {
         text.Add(reader.ReadLine());
      }

      reader.Close();
      reader.Dispose();
      return text;
   }

   public void WriteFile(List<string> text, string path)
   {
      FileInfo file = new FileInfo(path);

      if (!file.Exists)
      {
         throw new FileNotFoundException();
      }

      StreamWriter writer = file.CreateText();

      foreach(string line in text)
      {
         writer.WriteLine(line);
      }

      writer.Flush();
      writer.Close();
      writer.Dispose();
   }
}

7 个答案:

答案 0 :(得分:13)

  

...但是可以获得更细粒度的错误消息。

是。继续捕获IOException,并使用Exception.ToString()方法获取要显示的相对相关的错误消息。请注意,.NET Framework生成的异常将提供这些有用的字符串,但是如果要抛出自己的异常,则必须记住将该字符串插入Exception的构造函数中,如:

throw new FileNotFoundException("File not found");

另外,绝对地,根据Scott Dorman,使用using语句。但要注意的是,using语句实际上并不catch任何事情,这应该是它应该的方式。例如,您检查文件是否存在的测试将引入可能相当vexing的竞争条件。把它放在那里对你没有任何好处。所以,现在,对于读者我们有:

try {  
    using (StreamReader reader = file.OpenText()) {  
        // Your processing code here  
    }  
} catch (IOException e) {  
    UI.AlertUserSomehow(e.ToString());  
}

简而言之,对于基本文件操作:
1.使用using
2,将try / catch中的使用声明或函数换行catch es IOException
3.在Exception.ToString()中使用catch获取有用的错误消息
4.不要试图自己检测异常文件问题。让.NET为你做点什么。

答案 1 :(得分:7)

您应该更改的第一件事是调用StreamWriter和StreamReader将它们包装在using语句中,如下所示:

using (StreamReader reader = file.OpenText())
{
   List<string> text = new List<string>();
   while (!reader.EndOfStream)
   {
      text.Add(reader.ReadLine());
   }
}

这将负责为您调用Close和Dispose,并实际将其包装在try / finally块中,以便实际编译的代码如下所示:

StreamReader reader = file.OpenText();
try
{
   List<string> text = new List<string>();
   while (!reader.EndOfStream)
   {
      text.Add(reader.ReadLine());
   }
}
finally
{
   if (reader != null)
      ((IDisposable)reader).Dispose();
}

这样做的好处是,即使发生异常,也可以确保流关闭。

就任何更明确的异常处理而言,它实际上取决于你想要发生什么。在您的示例中,您明确地测试文件是否存在并抛出FileNotFoundException,这可能对您的用户来说已经足够了,但可能没有。

答案 2 :(得分:1)

  • 跳过File.Exists();要么在其他地方处理它,要么让CreateText()/ OpenText()提升它。
  • 最终用户通常只关心成功与否。如果它失败了,就这么说,他不想要细节。

我还没有找到一种内置的方法来获取有关.NET中出现故障的原因和原因的详细信息,但如果您使用CreateFile进行原生设置,则会有数以千计的错误代码可以告诉您出了什么问题。

答案 3 :(得分:1)

我没有看到检查文件是否存在以及抛出没有消息的FileNotFoundException的重点。框架将抛出​​FileNotFoundException本身,并带有消息。

您的示例的另一个问题是您应该使用try / finally模式或using语句来确保即使存在异常也可以正确处理您的一次性类。

我会这样做,如下所示,捕获方法之外的任何异常,并显示异常的消息:

public IList<string> ReadFile(string path)
{
    List<string> text = new List<string>();
    using(StreamReader reader = new StreamReader(path))
    {
      while (!reader.EndOfStream)      
      {         
         text.Add(reader.ReadLine());      
      }
    }
    return text;
}

答案 4 :(得分:0)

我会使用using语句来简化文件的关闭。见MSDN the C# using statement

来自MSDN:

  using (TextWriter w = File.CreateText("log.txt")) {
     w.WriteLine("This is line one");
     w.WriteLine("This is line two");
  }
  using (TextReader r = File.OpenText("log.txt")) {
     string s;
     while ((s = r.ReadLine()) != null) {
        Console.WriteLine(s);
     }
  }

答案 5 :(得分:0)

也许这不是您正在寻找的,但重新考虑您使用异常处理的那种。首先,异常处理不应被视为“用户友好”,至少只要您将程序员视为用户。

对此的总结可能是以下文章http://goit-postal.blogspot.com/2007/03/brief-introduction-to-exception.html

答案 6 :(得分:-2)

我会尝试检查文件。在调用读/写之前检查并在那里响应用户,而不是创建引发错误的开销并在以后捕获它,因为检查很容易。我确实理解提出错误的必要性,但在这种特殊情况下,简单检查imho将是一个更好的解决方案。我的意思是添加一个方法来检查文件是否存在。

此外,如果您事先检查文件是否退出,您知道如果您无法写入文件,则其他内容会阻止它。你也可以捕获多个例外,第一个匹配将被捕获 - 但你可能知道这个......