2008-09-17 66 views
13

通常我會發現自己以某種方式與文件進行交互,但在編寫代碼之後,我總是不確定它實際上是多麼的粗糙。問題是,我不完全確定文件相關的操作如何失敗,因此是處理預期的最佳方式。如何在執行文件時正確處理異常io

簡單的解決方案似乎只是爲了捕獲代碼拋出的任何IOException,並給用戶一個「無法訪問的文件」的錯誤消息,但它可能會得到更多的細粒度的錯誤消息。有沒有辦法確定這樣的錯誤之間的差異,例如文件被另一個程序鎖定,並且數據由於硬件錯誤而無法讀取?

鑑於以下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(); 
    } 
} 
+0

捕捉IOException並不完全足夠。類似OpenText的方法可以拋出其他異常,如UnauthorizedAccessException和ArgumentException。 – denver 2015-04-28 16:27:13

回答

11

...但是有可能得到一些更細粒度的錯誤信息。

是的。繼續並捕獲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/catchcatch ES IOException
3.在您的catch中使用Exception.ToString()獲取有用的錯誤消息
4.不要嘗試自己檢測特殊的文件問題。讓.NET爲你做投擲。

-2

我會試着打電話給你的讀/寫之前檢查的file.Exists和響應用戶那裏,而不是創建引發錯誤的開銷,因爲檢查後捕獲它是那麼容易使。我明白需要提出錯誤,但在這種情況下,簡單的檢查恕我直言將是一個更好的解決方案。我的意思是增加一個方法來檢查文件是否存在。

此外,如果您事先檢查文件是否退出,您知道別的東西在阻止它,如果你不能寫入它。你也可以捕捉到多個例外,第一個匹配的將被捕獲 - 但你可能知道這個...

7

你應該改變的第一件事是你調用StreamWriter和StreamReader將它們包裝在using語句中,像這樣:

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

這會照顧調用Close和處置爲你實際上將它包裝在一個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(); 
} 

的好處在這裏你確保流量在封閉前夕n如果發生異常。

至於更明確的異常處理,它真的取決於你想要發生什麼。在你的例子中,你明確地測試該文件是否存在並拋出一個FileNotFoundException,這對你的用戶來說可能是足夠的,但它可能不會。

+0

我確實知道使用指令但忘記了它。但是,我不知道它也添加了嘗試抓取。涼! – 2008-09-17 19:56:37

+0

嗯,它實際上增加了一個try/finally而不是try/catch。即使發生異常,也可以確保Dispose被調用。 – 2008-10-17 15:27:03

1
  • 跳過File.Exists();要麼在別處處理,要麼讓CreateText()/ OpenText()提升它。
  • 最終用戶通常只關心成功與否。如果失敗了,就這麼說吧,他不想要細節。

我還沒有找到一個內置的方式來獲得有關細節什麼,以及爲什麼東西.NET失敗了,但如果你去與本土的CreateFile你有成千上萬的錯誤代碼,它可以告訴你什麼地方出了錯。

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