回答:
私は過去にこれまでに数え切れないほどの回数をやりました、そして私がそれをするたびに、私は試みをすることさえ間違っていました。
ファイルのパーミッション(でもファイルの存在)がある揮発性 -彼らはいつでも変更することができます。特にマーフィーの法則のおかげで、ファイルをチェックしてから開こうとするまでの短い期間が含まれます。最初に確認する必要があることがわかっている地域にいる場合、変更はさらに起こりやすくなります。しかし、奇妙なことに、かなり静的である傾向があるテスト環境や開発環境では決して起こりません。これにより、問題を後で追跡することが困難になり、この種のバグが本番環境に移行しやすくなります。
これが意味することは、チェックにもかかわらず、ファイルのアクセス許可または存在が悪い場合でも、例外を処理できる必要があるということです。事前にファイルの権限を確認するかどうかに関係なく、例外処理コードが必要です。例外処理コードは、存在または権限チェックのすべての機能を提供します。さらに、このような例外ハンドラーは遅いことがわかっていますが、ディスクI / Oがさらに遅いことを覚えておくことが重要です... はるかに遅い...そして.Exists()関数を呼び出すか、アクセス許可をチェックすると、追加のトリップが強制されますファイルシステムから。
要約すると、ファイルを開こうとする前の最初のチェックは冗長であり、無駄です。例外処理に追加の利点はありません。実際にはパフォーマンスに悪影響を及ぼし、助けにはなりません。維持する必要のあるコードが増えるという点でコストが追加され、コードに微妙なバグが発生する可能性があります。最初のチェックを行うメリットはまったくありません。代わりに、ここでの正しいことは、ファイルを開いて、失敗した場合に優れた例外ハンドラーに努力することです。ファイルが存在するかどうかを確認するだけでも同じです。この推論は、すべての揮発性リソースに適用されます。
同様の問題でここに来る他の人のための簡単なヒント:
DropBoxなどのWeb同期アプリに注意してください。.NETで「using」ステートメント(Disposeパターン)が壊れていると思って2時間費やしました。
最終的に、Dropboxがファイルを同期するために、バックグラウンドで継続的にファイルの読み取りと書き込みを行っていることに気付きました。
Visual Studio Projectsフォルダーがどこにあると思いますか?もちろん「My Dropbox」フォルダの中。
そのため、アプリケーションをデバッグモードで実行すると、アプリケーションが読み書きしていたファイルもDropBoxから継続的にアクセスされ、DropBoxサーバーと同期されていました。これにより、ロック/アクセスの競合が発生しました。
したがって、少なくとも今では、より堅牢なファイルを開く関数(つまり、複数回試行するTryOpen())が必要であることを知っています。フレームワークの組み込み部分ではないことに驚いています。
[更新]
これが私のヘルパー関数です:
/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS)
{
FileStream fs = null;
int attempts = 0;
// Loop allow multiple attempts
while (true)
{
try
{
fs = File.Open(filePath, fileMode, fileAccess, fileShare);
//If we get here, the File.Open succeeded, so break out of the loop and return the FileStream
break;
}
catch (IOException ioEx)
{
// IOExcception is thrown if the file is in use by another process.
// Check the numbere of attempts to ensure no infinite loop
attempts++;
if (attempts > maximumAttempts)
{
// Too many attempts,cannot Open File, break and return null
fs = null;
break;
}
else
{
// Sleep before making another attempt
Thread.Sleep(attemptWaitMS);
}
}
}
// Reutn the filestream, may be valid or null
return fs;
}
using
とすると、呼び出し元はを使用する必要があります...
using
ここでは機能しません。使用ブロックの最後で、fs
強制的に閉じられます。呼び出し元に閉じられた(役に立たない)ファイルストリームを与えます!
ここにあなたが探している解決策があります
var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
System.Security.AccessControl.AccessControlActions.View,
MyPath);
if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
// Do your thing here...
}
これは、すべてのファイルのパスのビューに基づいて読み取りの新しいアクセス許可を作成し、それがファイルアクセス読み取りと等しいかどうかを確認します。
最初に、Joel Coehoornが言ったこと。
また、必要がない限り、try / catchの使用を避けたいという根底にある仮定を検討する必要があります。例外に依存するロジックを回避する一般的な理由(Exception
オブジェクトの作成のパフォーマンスが低い)は、ファイルを開いているコードとは関係ありません。
List<FileStream>
ディレクトリサブツリーのすべてのファイルを開いてにデータを入力するメソッドを作成していて、それらの多数にアクセスできないことが予想される場合は、ファイルを開く前にファイルのアクセス許可を確認して、ファイルを開かないようにするとよいでしょう。例外が多すぎます。しかし、それでも例外は処理します。また、これを行うメソッドを作成している場合は、プログラムの設計にひどい問題がある可能性があります。
public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds)
{
try
{
return File.Open(filePath, fileMode, fileAccess, fileShare);
}
catch (UnauthorizedAccessException unauthorizedAccessException)
{
if (attempts <= 0)
{
throw unauthorizedAccessException;
}
else
{
Thread.Sleep(attemptWaitInMilliseconds);
attempts--;
return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds);
}
}
}
attempts
リファレンスによって渡されるのですか?それは意味がありません。<=
だけでなく、のテストも行いません==
。
throw ex
は実際に正しいことだと思います。