113 votes

Comment pouvez-vous vérifier facilement si l’accès est refusé pour un fichier dans .NET ?

Fondamentalement, je voudrais vérifier si j’ai les droits pour ouvrir le fichier avant que j’ai effectivement essayer de l’ouvrir ; Je ne veux pas utiliser un try/catch pour cette vérification, je n’ai pas de. Y a-t-il une propriété d’accès de fichier que je peux vérifier avant la main ?

171voto

Joel Coehoorn Points 190579

Je l'ai fait un nombre incalculable de fois dans le passé, et presque à chaque fois que je l'ai fait je me suis trompé de même tenter l'expérience.

Les autorisations de fichier (même de l'existence de fichier) sont volatils — ils peuvent changer à tout moment. Grâce à la Loi de Murphy c' particulièrement comprend la brève période entre le moment où vous vérifiez le fichier et lorsque vous essayez de l'ouvrir. Un changement est encore plus probable si vous êtes dans une zone où vous savez que vous devez vérifier d'abord. Pourtant, étrangement, cela n'arrivera jamais dans vos essais ou des environnements de développement, qui ont tendance à être assez statique. Cela rend le problème difficile de retrouver plus tard, et il est facile pour ce genre de bug pour en faire de la production.

Ce que cela signifie est que vous devez toujours être en mesure de gérer l'exception, si les autorisations de fichier ou de l'existence sont mauvais, en dépit de votre chèque. Code de gestion des exceptions est nécessaire, si oui ou non vous vérifiez les permissions de ce fichier à l'avance. Code de gestion des exceptions fournit toutes les fonctionnalités de l'existence ou de contrôles d'autorisation. En outre, tandis que les gestionnaires d'exceptions de ce genre sont connus pour être lent, il est important de se rappeler que les i/o disque est encore plus lent... un beaucoup plus lent... et l'appel de la .Exists() de la fonction ou de la vérification des autorisations force supplémentaire de voyage à l'extérieur du système de fichiers.

En résumé, une vérification initiale avant d'essayer d'ouvrir le fichier est à la fois redondant et inutile. Il n'y a aucun avantage supplémentaire sur la gestion des exceptions, il va vraiment mal, pas d'aide, votre performance, il augmente le coût en termes de code qui doit être maintenu, et il peut introduire des bogues subtils dans votre code. Il n'est tout simplement pas à l'envers à tout pour faire de la vérification initiale. Au lieu de cela, la bonne chose ici est de simplement essayer d'ouvrir le fichier et de mettre vos efforts dans un bon gestionnaire d'exception en cas d'échec. Le même est vrai même si vous êtes juste de vérifier si le fichier existe. Ce raisonnement s'applique à toutes les ressources volatiles.

30voto

Mark Brackett Points 46824

Alors que je suis d'accord que ce n'est pas sans créer une situation de concurrence, je crois FileIOPermission a la réponse si vous avez vraiment envie de le faire:

new FileIOPermission(FileIOPermissionAccess.Read, path).Demand();

Edit: Comme l'a souligné, c'est pour le FX autorisations - pas le fichier sous-jacent système d'autorisations - il seulement des réponses et demi (le demi) de votre question.

Si vous êtes intéressés à obtenir les autorisations NTFS, vous aurez pour P/Invoke AccessCheck, AuthzAccessCheck, ou GetEffectiveRightsFromACL. Vous auriez également besoin de récupérer le réel de l'ACL du fichier, et être méfier de l'énumération des autorisations sur des serveurs distants. juste utiliser cette agréable et facile code.

26voto

Ash Points 31541

Un conseil pour quelqu'un d'autre de venir ici avec un problème similaire:

Watch out pour la synchronisation web applications comme DropBox. Je viens de passer 2 heures à réfléchir à la section "utilisation" déclaration (modèle dispose) est cassé .NET.

J'ai finalement réalisé que Dropbox est continuellement à la lecture et l'écriture de fichiers en arrière-plan, afin de les synchroniser.

Devinez d'où mon dossier Projets Visual Studio est situé? À l'intérieur de la "My Dropbox" dossier de cours.

Donc comme je l'ai couru mon application en mode Debug, les fichiers dont il a été la lecture et l'écriture ont également été constamment accessible par DropBox pour être synchronisé avec le serveur DropBox. Cela a provoqué le blocage de l'accès des conflits.

Si au moins je sais maintenant que j'ai besoin d'un plus robuste d'ouverture de Fichier de la fonction (c'est à dire TryOpen() qui permettra de faire plusieurs tentatives). Je suis surpris qu'il n'est pas déjà intégré dans le cadre de le cadre.

[Mise à jour]

Voici ma fonction d'assistance:

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

4voto

Robert Rossney Points 43767

Tout d'abord, ce que Joel Coehoorn dit.

Aussi: vous devez examiner les hypothèses qui sous-tendent votre désir d'éviter d'utiliser try/catch, sauf si vous avez. La raison classique pour éviter la logique qui dépend des exceptions (la création d' Exception objets effectue mal) n'est probablement pas pertinentes du code de l'ouverture d'un fichier.

Je suppose que si vous écrivez une méthode qui remplit un List<FileStream> par l'ouverture de tous les fichiers dans une arborescence de répertoires et vous attend un grand nombre d'entre eux à être inaccessible, vous pouvez vouloir vérifier les autorisations de fichier avant d'essayer d'ouvrir un fichier de sorte que vous n'avez pas trop d'exceptions. Mais vous auriez encore traiter l'exception. Aussi, il y a probablement quelque chose de mal avec votre conception du programme, si vous écrivez une méthode qui fait cela.

2voto

Eric Lippert explique probablement pourquoi Joel est juste ici

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X