Как правильно обрабатывать исключения при выполнении ввода-вывода файлов

StackOverflow https://stackoverflow.com/questions/86766

Вопрос

Часто я ловлю себя на том, что каким-то образом взаимодействую с файлами, но после написания кода я всегда не уверен, насколько он прост на самом деле.Проблема в том, что я не совсем уверен, как операции, связанные с файлами, могут завершиться неудачей и, следовательно, каков наилучший способ обработки ожиданий.

Казалось бы, простым решением было бы просто перехватить любые 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();
   }
}
Это было полезно?

Решение

... но возможно ли получить немного более детализированные сообщения об ошибках?

ДА.Иди вперед и лови IOException, и использовать Exception.ToString() способ получения относительно релевантного сообщения об ошибке для отображения.Обратите внимание, что исключения, сгенерированные .NET Framework, будут предоставлять эти полезные строки, но если вы собираетесь создать свое собственное исключение, вы должны не забыть вставить эту строку в Exceptionконструктор, как:

throw new FileNotFoundException("File not found");

Кроме того, абсолютно, согласно Скотт Дорман, используй это 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/catch это catches IOException
3.Использование Exception.ToString() в вашем catch чтобы получить полезное сообщение об ошибке
4.Не пытайтесь самостоятельно обнаружить исключительные проблемы с файлами.Позвольте .NET сделать это за вас.

Другие советы

Первое, что вам следует изменить, - это ваши вызовы 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, которого может быть достаточно для ваших пользователей, но может и не быть.

  • Пропустите файл.Существует();либо обработайте его в другом месте, либо позвольте CreateText() / OpenText() вызвать его.
  • Конечного пользователя обычно волнует только то, удастся это или нет.Если это не удастся, просто скажи об этом, ему не нужны подробности.

Я не нашел встроенного способа получить подробную информацию о том, что и почему что-то не удалось в .NET, но если вы перейдете на native с CreateFile, у вас будут тысячи кодов ошибок, которые могут подсказать вам, что пошло не так.

Я не вижу смысла проверять наличие файла и выдавать исключение 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;
}

Я бы использовал инструкцию 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);
     }
  }

Возможно, это не то, что вы ищете, но пересмотрите тип обработки исключений, который вы используете.Сначала обработку исключений не следует рассматривать как "удобную для пользователя", по крайней мере, до тех пор, пока вы думаете о программисте как о пользователе.

Итогом для этого может стать следующая статья http://goit-postal.blogspot.com/2007/03/brief-introduction-to-exception.html .

Я бы попробовал проверить наличие файла.Существует до вызова вашего режима чтения / записи и ответа пользователю там, вместо того, чтобы создавать накладные расходы на выдачу ошибки и ее последующее обнаружение, поскольку проверку так легко выполнить.Я понимаю необходимость возникновения ошибок, но в данном конкретном случае простая проверка, имхо, была бы лучшим решением.Я имею в виду добавить еще один метод для проверки, существует ли файл.

Также, если вы заранее проверяете, завершается ли файл, вы знаете, что что-то еще блокирует его, если вы не можете выполнить запись в него.Также вы можете перехватить несколько исключений, которые будут перехвачены первыми, но вы, вероятно, знаете это...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top