ファイル IO の実行時に例外を適切に処理する方法
-
01-07-2019 - |
質問
多くの場合、何らかの方法でファイルを操作していることに気づきますが、コードを書いた後、それが実際にどの程度強力であるかは常にわかりません。問題は、ファイル関連の操作がどのように失敗するのか、したがって期待に対処する最善の方法がまったくわからないことです。
簡単な解決策は、コードによってスローされた 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();
}
}
解決
...しかし、もう少し詳細なエラー メッセージを取得することは可能でしょうか。
はい。さあ、捕まえてください 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
それ catch
エス 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 をスローします。これはユーザーにとっては十分かもしれませんが、そうでない場合もあります。
- File.Exists() をスキップします。別の場所で処理するか、CreateText()/OpenText() で発生させます。
- エンドユーザーは通常、それが成功したかどうかだけを気にします。それが失敗した場合は、ただそう言ってください、彼は詳細を望んでいません。
.NET で何が失敗したのか、なぜ失敗したのかの詳細を取得する組み込みの方法は見つかりませんでしたが、CreateFile をネイティブに使用すると、何が問題だったのかを知ることができる何千ものエラー コードが得られます。
ファイルの存在を確認し、メッセージなしで FileNotFoundException をスローする意味がわかりません。フレームワークは、FileNotFoundException 自体をメッセージとともにスローします。
この例のもう 1 つの問題は、例外が発生した場合でも、使い捨てクラスが適切に破棄されるようにするために、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 .
チェックは非常に簡単なので、エラーを発生させて後でキャッチするオーバーヘッドを作成する代わりに、読み取り/書き込みを呼び出す前に file.Exists をチェックしてそこでユーザーに応答することを試みます。エラーを発生させる必要性は理解していますが、特にこのケースでは、単純なチェックを行う方が良い解決策だと思います。私が言いたいのは、ファイルが存在するかどうかを確認するメソッドをもう 1 つ追加するということです。
また、ファイルが存在するかどうかを事前に確認しておけば、ファイルに書き込めない場合、他の何かがファイルをブロックしていることがわかります。また、複数の例外をキャッチすることもでき、最初に一致した例外がキャッチされます。しかし、これはおそらくご存知でしょう...