web-dev-qa-db-ja.com

.NETのファイルへのアクセスが拒否されているかどうかを簡単に確認するにはどうすればよいですか?

基本的に、実際にファイルを開こうとする前に、ファイルを開く権限があるかどうかを確認したいと思います。必要がない限り、このチェックにtry/catchを使用したくありません。事前に確認できるファイルアクセスプロパティはありますか?

98
Horas

私は過去にこれを数え切れないほど行ってきましたが、それを行うたびに、試行することさえ間違っていました。

ファイルのアクセス許可(ファイルの存在さえ)はvolatileです—それらはいつでも変更できます。マーフィーの法則のおかげで、この特にには、ファイルをチェックしてから開こうとするまでの短い期間が含まれます。最初に確認する必要があるとわかっている地域にいる場合、変更はさらに起こりやすくなります。しかし、奇妙なことに、テスト環境や開発環境では決して発生しないため、かなり静的な傾向があります。これにより、後で問題を追跡するのが難しくなり、この種のバグを簡単に本番環境に組み込むことができます。

これが意味することは、ファイルの許可または存在が悪い場合、チェックにもかかわらず例外を処理できる必要があるということです。例外処理コードは必須で、ファイルのアクセス許可を事前に確認するかどうかに関係ありません。例外処理コードは、存在または権限チェックの機能のallを提供します。さらに、このような例外ハンドラーは遅いことが知られていますが、ディスクI/Oはさらに遅いことを覚えておくことが重要です... lot slow ...... .Exists()関数またはアクセス許可を確認すると、ファイルシステムがさらにトリップされます。

要約すると、ファイルを開こうとする前の初期チェックは冗長であり、無駄です。例外処理に勝る追加の利点はありません。パフォーマンスを実際に傷つけますが、助けにはならず、維持しなければならないコードが増えるという点でコストが追加され、コードに微妙なバグが発生する可能性があります。最初のチェックを行うことにはまったく利点がありません。代わりに、ここでの正しいことは、ファイルを開いて、失敗した場合は適切な例外ハンドラーに努力することです。ファイルが存在するかどうかを確認するだけでも、同じことが言えます。この推論は、any volatileリソースに適用されます。

151
Joel Coehoorn

同様の問題でここに来る他の人のための簡単なヒント:

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

あなたが探しているソリューションはこちらです

var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
                                            System.Security.AccessControl.AccessControlActions.View,
                                            MyPath);

if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
    // Do your thing here...
}

これにより、すべてのファイルのパスのビューに基づいて読み取りの新しいアクセス許可が作成され、ファイルアクセス読み取りと等しいかどうかが確認されます。

4
dj shahar

まず、Joel Coehoornが言ったこと。

また、必要がない限り、try/catchの使用を避けたいという願望の根底にある仮定を検討する必要があります。例外に依存するロジック(Exceptionオブジェクトの作成のパフォーマンスが低い)を回避する一般的な理由は、ファイルを開くコードにはおそらく関係ありません。

ディレクトリサブツリー内のすべてのファイルを開くことでList<FileStream>を生成するメソッドを作成しており、多数のファイルにアクセスできないと予想した場合、ファイルを開く前にファイルのアクセス許可を確認する必要があると思います例外が多すぎないこと。ただし、例外は引き続き処理します。また、これを行うメソッドを書いている場合、おそらくプログラムの設計に何かひどい問題があります。

3
Robert Rossney
public static bool IsFileLocked(string filename)
        {
            bool Locked = false;
            try
            {
                FileStream fs =
                    File.Open(filename, FileMode.OpenOrCreate,
                    FileAccess.ReadWrite, FileShare.None);
                fs.Close();
            }
            catch (IOException ex)
            {
                Locked = true;
            }
            return Locked;
        }
0
Omid Maturi