web-dev-qa-db-fra.com

Déterminer si le fichier existe à l'aide de c # et résoudre le chemin UNC

J'essaie d'écrire une fonction pour déterminer si un fichier existe. Les deux méthodes s'avèrent renvoyer des résultats incohérents (fileExists () semble fournir des résultats précis, par rapport à isFileFound (), qui renvoie des faux positifs - je m'attendais à une exception lors de la tentative de création de l'instance).

protected bool isFileFound(string path, string fileName)
    {
        System.IO.FileInfo fi = null;

        bool found = false;
        try
        {
            fi = new System.IO.FileInfo(path + fileName);
            found = true;
        }
        catch (Exception e)
        {
            baselogger.Fatal(e.Message + " " + e.StackTrace + " \n" + path + fileName);
        }

        return found;
    }

    protected bool fileExists(string path, string pattern)
    {
        bool success = false;

        try
        {
            success = File.Exists(path + pattern);
        }
        catch (Exception e)
        {
            baselogger.Warn(e.Message + " " + e.StackTrace + " " + e.Source);
        }

        return success;
    }

Aucun des deux ne semble pouvoir résoudre un chemin UNC de la syntaxe suivante: \\ abcserver\c $\xyzfolder\foo.bar

Toute idée de la raison pour laquelle le chemin UNC échoue pour ces méthodes serait grandement appréciée.

27
steve_mtl

Vous pouvez créer un FileInfo pour un fichier inexistant. Mais vous pouvez ensuite vérifier la propriété FileInfo.Exists pour déterminer si le fichier existe, par exemple:

FileInfo fi = new FileInfo(somePath);
bool exists = fi.Exists;

pdate: Dans un court test, cela a également fonctionné pour les chemins UNC, par exemple comme ça:

FileInfo fi = new FileInfo(@"\\server\share\file.txt");
bool exists = fi.Exists;

Êtes-vous sûr que le compte (sous lequel votre application s'exécute) a accès au partage. Je pense que (par défaut) des droits administratifs sont nécessaires pour accéder au partage "c $".

37
M4N

Voir cette question:
comment pouvez-vous facilement vérifier si l'accès est refusé à un fichier dans .NET?

La version courte de cette question est que vous ne le faites pas, car le système de fichiers est volatile. Essayez simplement d'ouvrir le fichier et de détecter l'exception en cas d'échec.

La raison pour laquelle votre méthode isFileFound ne fonctionne pas est que la structure FileInfo que vous utilisez peut également être utilisée pour créer des fichiers. Vous pouvez créer un objet FileInfo avec les informations souhaitées pour un fichier inexistant, appeler sa méthode .Create(), et vous avez défini vos propriétés souhaitées en même temps.

Je soupçonne que la raison pour laquelle le chemin UNC échoue est soit 1) un problème d'autorisations d'accès au partage administrateur de l'utilisateur exécutant votre application, ou 2) Le symbole $ Lance la méthode désactivé, soit parce qu'il n'est pas entré correctement, soit en raison d'un bogue dans l'implémentation .Exists () sous-jacente.

Mise à jour:

Lorsque je poste cette suggestion, je reçois presque toujours une plainte concernant les performances des exceptions. Parlons de ça. Oui, la gestion des exceptions coûte cher: très cher. Il y a peu de choses que vous pouvez faire dans la programmation qui sont plus lentes. Mais vous savez ce que ces quelques choses sont? E/S disque et réseau. Voici un lien qui montre le coût des E/S disque et E/S réseau:

https://Gist.github.com/jboner/2841832

Numéros de comparaison de latence 
 -------------------------- 
 Référence de cache L1 0,5 ns 
 Branche erreur de prévision 5 ns 
 Référence du cache L2 7 ns 14x Cache L1 
 Verrouillage/déverrouillage Mutex 25 ns 
 Référence de la mémoire principale 100 ns 20x cache L2, 200x cache L1 
 Compression 1 000 octets avec Zippy 3 000 ns 
 Envoi de 1 000 octets sur un réseau à 1 Gbit/s 10 000 ns 0,01 ms 
 Lecture 4K aléatoire sur SSD * 150 000 ns 0,15 ms 
 Lecture séquentielle de 1 Mo à partir de la mémoire 250 000 ns 0,25 ms 
 Aller-retour dans le même centre de données 500 000 ns 0,5 ms 
 Lecture séquentielle de 1 Mo à partir du SSD * 1 000 000 ns 1 ms Mémoire 4X 
 Recherche de disque 10 000 000 ns 10 ms 20x Aller-retour du centre de données 
 Lire 1 Mo séquentiellement à partir du disque 20 000, 000 ns 20 ms 80x mémoire, 20X SSD 
 Envoyer le paquet CA-> Pays-Bas-> CA 150 000 000 ns 150 ms

Si penser en nanosecondes n'est pas votre truc, voici un autre lien qui normalise un cycle de processeur en 1 seconde et évolue à partir de là:

http://blog.codinghorror.com/the-infinite-space-between-words/

 1 cycle de processeur 0,3 ns 1 s 
 Accès au cache de niveau 1 0,9 ns 3 s 
 Accès au cache de niveau 2 2,8 ns 9 s 
 Accès au cache de niveau 3 12,9 ns 43 s 
 Accès à la mémoire principale 120 ns 6 min 
 E/S disque à semi-conducteurs 50-150 μs 2-6 jours 
 E/S disque rotatif 1-10 ms 1-12 mois 
 Internet: SF à NYC 40 ms 4 ans 
 Internet: SF à UK 81 ms 8 ans 
 Internet: SF à AUS 183 ms 19 ans 
 OS virt . redémarrage 4 s 423 ans 
 Délai d'expiration de la commande SCSI 30 s 3000 ans 
 Virt. matériel. redémarrage 40 s 4000 ans 
 redémarrage du système physique 5 m 32 millénaires

En prenant même le meilleur des cas pour les exceptions, vous pouvez accéder à la mémoire au moins 480 fois en attendant la première réponse d'un disque, et cela suppose un SSD très rapide. Beaucoup d'entre nous ont encore besoin de faire tourner des disques durs, où les choses empirent, bien pire.

Et ce n'est que le début de l'histoire. Lorsque vous utilisez .Exists(), vous encourez ce supplémentaire coût (et c'est un ajout: vous devez refaire le même travail lorsque vous allez ouvrir le fichier) on = tous les tentative. Vous payez ces coûts, que le fichier existe ou non, car le disque doit toujours le rechercher dans ses tables de fichiers. Avec la méthode d'exception, vous ne payez le coût supplémentaire de déroulement de la pile d'appels qu'en cas d'échec.

En d'autres termes, oui: les exceptions sont terriblement coûteuses. Mais par rapport à la vérification du disque, c'est toujours plus rapide: et pas seulement par une petite marge. Heureusement, il est peu probable que cela améliore les performances générales de votre application ... mais je veux quand même mettre au lit l'argument "les exceptions sont lentes" pour cette tâche spécifique.

13
Joel Coehoorn

Cela peut ou non être le cas, mais pourriez-vous joindre à votre chemin un nom de fichier incorrect pour l'un de vos cas.

Ce:

success = File.Exists (chemin + modèle);

contre:

success = File.Exists (Path.Join (chemin, modèle));

3
llamaoo7

Edit: Eh bien, je viens de réaliser que file.exists fonctionne bien. Ce serait certainement la méthode préférée. Le code ci-dessous vous donne la possibilité de demander à Windows d'authentifier l'utilisateur si le partage doit être accessible sous un autre compte de domaine. Pourrait aider quelqu'un un jour, je vais donc laisser le code ici.

Si vous devez accéder à un chemin UNC ou à un partage administrateur à l'aide de différentes informations d'identification: MSDN

Pour bootstrap utilisation de WNetAddConnection2 utilisez ce code:

using System;
using System.Runtime.InteropServices;

namespace Win32Api
{
    public enum ResourceScope
    {
        RESOURCE_CONNECTED = 1,
        RESOURCE_GLOBALNET,
        RESOURCE_REMEMBERED,
        RESOURCE_RECENT,
        RESOURCE_CONTEXT
    };

    public enum ResourceType
    {
        RESOURCETYPE_ANY,
        RESOURCETYPE_DISK,
        RESOURCETYPE_PRINT,
        RESOURCETYPE_RESERVED = 8
    };

    [Flags]
    public enum ResourceUsage
    {
        RESOURCEUSAGE_CONNECTABLE = 0x00000001,
        RESOURCEUSAGE_CONTAINER = 0x00000002,
        RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
        RESOURCEUSAGE_SIBLING = 0x00000008,
        RESOURCEUSAGE_ATTACHED = 0x00000010,
        RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE |
                             RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
    };

    public enum ResourceDisplayType
    {
        RESOURCEDISPLAYTYPE_GENERIC,
        RESOURCEDISPLAYTYPE_DOMAIN,
        RESOURCEDISPLAYTYPE_SERVER,
        RESOURCEDISPLAYTYPE_SHARE,
        RESOURCEDISPLAYTYPE_FILE,
        RESOURCEDISPLAYTYPE_GROUP,
        RESOURCEDISPLAYTYPE_NETWORK,
        RESOURCEDISPLAYTYPE_ROOT,
        RESOURCEDISPLAYTYPE_SHAREADMIN,
        RESOURCEDISPLAYTYPE_DIRECTORY,
        RESOURCEDISPLAYTYPE_TREE,
        RESOURCEDISPLAYTYPE_NDSCONTAINER
    };

    [StructLayout(LayoutKind.Sequential)]
    public class NetResource
    {
        public ResourceScope Scope;
        public ResourceType Type;
        public ResourceDisplayType DisplayType;
        public ResourceUsage Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    };

    [Flags]
    public enum AddConnectionOptions
    {
        CONNECT_UPDATE_PROFILE = 0x00000001,
        CONNECT_UPDATE_RECENT = 0x00000002,
        CONNECT_TEMPORARY = 0x00000004,
        CONNECT_INTERACTIVE = 0x00000008,
        CONNECT_Prompt = 0x00000010,
        CONNECT_NEED_DRIVE = 0x00000020,
        CONNECT_REFCOUNT = 0x00000040,
        CONNECT_REDIRECT = 0x00000080,
        CONNECT_LOCALDRIVE = 0x00000100,
        CONNECT_CURRENT_MEDIA = 0x00000200,
        CONNECT_DEFERRED = 0x00000400,
        CONNECT_RESERVED = unchecked((int)0xFF000000),
        CONNECT_COMMANDLINE = 0x00000800,
        CONNECT_CMD_SAVECRED = 0x00001000,
        CONNECT_CRED_RESET = 0x00002000
    }

    public static class NativeMethods
    {
        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]
        public static extern int WNetAddConnection2(
            NetResource netResource, string password,
            string username, AddConnectionOptions options);

        [DllImport("mpr.dll")]
        public static extern int WNetCancelConnection2(string name, int flags,
        bool force);

    }
}
1
HAL9000

Je suis donc allé avec le

bool success = File.Exists(path + Filename);

, par opposition à l'utilisation de la route FileInfo.

Merci pour toutes les suggestions!

1
steve_mtl

Cela peut vous aider:
http://www.codeplex.com/FileDirectoryPath
Ce sont NDepend.Helpers.FilePathDirectory , qui ont entre autres une "API de vérification de la validité du chemin" qui peuvent être utiles.

1
Click Ok