Domanda

Spesso mi ritrovo a interagire in qualche modo con i file, ma dopo aver scritto il codice sono sempre incerto su quanto sia effettivamente robusto.Il problema è che non sono del tutto sicuro di come le operazioni relative ai file possano fallire e, quindi, del modo migliore per gestire le aspettative.

La soluzione semplice sembrerebbe essere quella di catturare eventuali IOException lanciate dal codice e fornire all'utente un messaggio di errore "File inaccessibile", ma è possibile ottenere messaggi di errore un po' più dettagliati.Esiste un modo per determinare la differenza tra errori quali il blocco di un file da parte di un altro programma e l'illeggibilità dei dati a causa di un errore hardware?

Dato il seguente codice C#, come gestiresti gli errori in modo intuitivo (il più informativo possibile)?

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();
   }
}
È stato utile?

Soluzione

...ma è possibile ricevere messaggi di errore un po' più dettagliati.

SÌ.Vai avanti e prendi IOException, e utilizzare il file Exception.ToString() metodo per ottenere un messaggio di errore relativamente rilevante da visualizzare.Tieni presente che le eccezioni generate da .NET Framework forniranno queste stringhe utili, ma se intendi generare la tua eccezione, devi ricordarti di inserire quella stringa nel Exception's costruttore, come:

throw new FileNotFoundException("File not found");

Inoltre, assolutamente, come da Scott Dormann, usa quello using dichiarazione.La cosa da notare, però, è che il using l'affermazione in realtà non lo fa catch qualsiasi cosa, ed è così che dovrebbe essere.Il tuo test per vedere se il file esiste, ad esempio, introdurrà una condizione di competizione che potrebbe essere piuttosto irritante.Non ti fa davvero bene averlo lì dentro.Quindi, ora, per il lettore abbiamo:

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

In breve, per le operazioni di base sui file:
1.Utilizzo using
2, racchiudi l'istruzione o la funzione using in a try/catch Quello catches IOException
3.Utilizzo Exception.ToString() nel tuo catch per ottenere un utile messaggio di errore
4.Non provare a rilevare da solo problemi eccezionali relativi ai file.Lascia che .NET faccia il lancio per te.

Altri suggerimenti

La prima cosa che dovresti cambiare sono le chiamate a StreamWriter e StreamReader per racchiuderle in un'istruzione using, come questa:

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

Questo si occuperà di chiamare Close e Dispose per te e lo avvolgerà effettivamente in un blocco try/finally in modo che il codice effettivamente compilato assomigli a questo:

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();
}

Il vantaggio qui è che ti assicuri che il flusso venga chiuso anche se si verifica un'eccezione.

Per quanto riguarda la gestione delle eccezioni più esplicita, dipende davvero da cosa vuoi che accada.Nel tuo esempio provi esplicitamente se il file esiste e lanci una FileNotFoundException che potrebbe essere sufficiente per i tuoi utenti ma potrebbe non esserlo.

  • Salta File.Exists();gestiscilo altrove o lascia che CreateText()/OpenText() lo sollevi.
  • All'utente finale di solito interessa solo se ha successo o meno.Se fallisce, dillo e basta, non vuole dettagli.

Non ho trovato un modo integrato per ottenere dettagli su cosa e perché qualcosa non è riuscito in .NET, ma se diventi nativo con CreateFile hai migliaia di codici di errore che possono dirti cosa è andato storto.

Non vedo il punto nel verificare l'esistenza di un file e lanciare una FileNotFoundException senza messaggio.Il framework lancerà la FileNotFoundException stessa, con un messaggio.

Un altro problema con il tuo esempio è che dovresti utilizzare il modello try/finally o l'istruzione using per assicurarti che le tue classi usa e getta siano smaltite correttamente anche quando c'è un'eccezione.

Lo farei in un modo simile al seguente, rilevare qualsiasi eccezione al di fuori del metodo e visualizzare il messaggio dell'eccezione:

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;
}

Vorrei utilizzare l'istruzione using per semplificare la chiusura del file.Vedere MSDN l'istruzione using C#

Da 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);
     }
  }

Forse questo non è quello che stai cercando, ma riconsidera il tipo di gestione delle eccezioni che stai utilizzando.Inizialmente la gestione delle eccezioni non dovrebbe essere considerata "user-friendly", almeno finché si pensa a un programmatore come a un utente.

Un riassunto potrebbe essere il seguente articolo http://goit-postal.blogspot.com/2007/03/brief-introduction-to-exception.html .

Vorrei provare a verificare la presenza di file.Exists prima di chiamare la lettura/scrittura e rispondere all'utente lì, invece di creare il sovraccarico di sollevare un errore e rilevarlo in seguito poiché il controllo è così facile da eseguire.Capisco la necessità di segnalare errori, ma in questo caso particolare un semplice controllo sarebbe una soluzione migliore.Ciò che intendo è aggiungere un altro metodo per verificare se il file esiste.

Inoltre, se controlli in anticipo se il file esce, sai che qualcos'altro lo sta bloccando se non puoi scriverci.Inoltre puoi catturare più eccezioni, verrà catturata la prima che corrisponde, ma probabilmente lo sai...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top