19

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

简单的解决方案似乎只是捕获代码抛出的任何 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();
   }
}
4

6 回答 6

15

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

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

throw new FileNotFoundException("File not found");

此外,绝对按照Scott Dorman的说法,使用该using声明。但是,要注意的是,该using语句实际上并没有catch任何作用,这应该是它应该的方式。例如,您检查文件是否存在的测试将引入可能相当令人烦恼的竞争条件。把它放在那里对你没有任何好处。所以,现在,对于读者,我们有:

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

简而言之,对于基本的文件操作:
1. 使用using
2,将 using 语句或函数包装在一个try/ catchthat catches中IOException
3. 使用Exception.ToString()in yourcatch以获得有用的错误消息
4. 不要尝试自己检测异常文件问题。让 .NET 为您完成任务。

于 2008-09-18T07:03:21.767 回答
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 ,这对您的用户来说可能就足够了,但可能还不够。

于 2008-09-17T19:43:39.357 回答
1
  • 跳过 File.Exists(); 要么在别处处理它,要么让 CreateText()/OpenText() 提升它。
  • 最终用户通常只关心它是否成功。如果失败了,就这么说吧,他不要细节。

我还没有找到一种内置的方法来获取有关 .NET 中失败的原因和原因的详细信息,但是如果您使用 CreateFile 本地化,那么您有成千上万的错误代码可以告诉您出了什么问题。

于 2008-09-17T19:49:07.737 回答
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;
}
于 2008-09-17T19:52:15.810 回答
0

我会使用 using 语句来简化关闭文件的过程。请参阅MSDN C# using 语句

来自 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);
     }
  }
于 2008-09-17T19:49:16.237 回答
0

也许这不是您要寻找的,但请重新考虑您使用的异常处理类型。起初,不应将异常处理视为“用户友好的”,至少只要您将程序员视为用户。

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

于 2008-09-17T19:55:14.897 回答