67 votes

Obtenez rapidement tous les fichiers et répertoires dans un chemin spécifique

Je suis entrain de créer une application de sauvegarde où c# de l'analyse d'un répertoire. Avant je utiliser pour avoir quelque chose comme cela dans le but de récupérer tous les fichiers et sous-fichiers dans un répertoire:

DirectoryInfo di = new DirectoryInfo("A:\\");
var directories= di.GetFiles("*", SearchOption.AllDirectories);

foreach (FileInfo d in directories)
{
       //Add files to a list so that later they can be compared to see if each file
       // needs to be copid or not
}

Le seul problème avec cela est que, parfois, un fichier ne peut pas être consulté et j'ai plusieurs erreurs. un exemple d'une erreur que je reçois est:error

Par conséquent, j'ai créé une méthode récursive qui analyse tous les fichiers dans le répertoire courant. Si là où les répertoires de ce répertoire, puis la méthode sera appelée de nouveau de passage de ce répertoire. La bonne chose à propos de cette méthode est que j'ai pu placer les fichiers à l'intérieur d'un bloc try catch me donnant la possibilité d'ajouter ces fichiers à une Liste si aucun des erreurs et ajouter le répertoire à l'autre liste si j'avais des erreurs.

try
{
    files = di.GetFiles(searchPattern, SearchOption.TopDirectoryOnly);               
}
catch
{
     //info of this folder was not able to get
     lstFilesErrors.Add(sDir(di));
     return;
}

Si cette méthode fonctionne très bien le seul problème est que lorsque je scanne un grand répertoire, il prend beaucoup de temps. Comment ai-je pu accélérer ce processus? Ma méthode est présent en cas de besoin.

private void startScan(DirectoryInfo di)
{
    //lstFilesErrors is a list of MyFile objects
    // I created that class because I wanted to store more specific information
    // about a file such as its comparePath name and other properties that I need 
    // in order to compare it with another list

    // lstFiles is a list of MyFile objects that store all the files
    // that are contained in path that I want to scan

    FileInfo[] files = null;
    DirectoryInfo[] directories = null;
    string searchPattern = "*.*";

    try
    {
        files = di.GetFiles(searchPattern, SearchOption.TopDirectoryOnly);               
    }
    catch
    {
        //info of this folder was not able to get
        lstFilesErrors.Add(sDir(di));
        return;
    }

    // if there are files in the directory then add those files to the list
    if (files != null)
    {
        foreach (FileInfo f in files)
        {
            lstFiles.Add(sFile(f));
        }
    }


    try
    {
        directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
    }
    catch
    {
        lstFilesErrors.Add(sDir(di));
        return;
    }

    // if that directory has more directories then add them to the list then 
    // execute this function
    if (directories != null)
        foreach (DirectoryInfo d in directories)
        {
            FileInfo[] subFiles = null;
            DirectoryInfo[] subDir = null;

            bool isThereAnError = false;

            try
            {
                subFiles = d.GetFiles();
                subDir = d.GetDirectories();

            }
            catch
            {
                isThereAnError = true;                                                
            }

            if (isThereAnError)
                lstFilesErrors.Add(sDir(d));
            else
            {
                lstFiles.Add(sDir(d));
                startScan(d);
            }


        }

}

Ant le problème si j'essaie de gérer l'exception avec quelque chose comme:

DirectoryInfo di = new DirectoryInfo("A:\\");
FileInfo[] directories = null;
            try
            {
                directories = di.GetFiles("*", SearchOption.AllDirectories);

            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine("There was an error with UnauthorizedAccessException");
            }
            catch
            {
                Console.WriteLine("There was antother error");
            }

Est que si une exception se produit, alors je n'ai pas de fichiers.

44voto

Tono Nam Points 4465

Cette méthode est beaucoup plus rapide. Vous ne pouvez téléphoner que lorsque vous placez beaucoup de fichiers dans un répertoire. Mon disque dur externe A: \ contient presque 1 terabit, ce qui fait une grande différence lorsque vous traitez beaucoup de fichiers.

 static void Main(string[] args)
{
    DirectoryInfo di = new DirectoryInfo("A:\\");
    FullDirList(di, "*");
    Console.WriteLine("Done");
    Console.Read();
}

static List<FileInfo> files = new List<FileInfo>();  // List that will hold the files and subfiles in path
static List<DirectoryInfo> folders = new List<DirectoryInfo>(); // List that hold direcotries that cannot be accessed
static void FullDirList(DirectoryInfo dir, string searchPattern)
{
    // Console.WriteLine("Directory {0}", dir.FullName);
    // list the files
    try
    {
        foreach (FileInfo f in dir.GetFiles(searchPattern))
        {
            //Console.WriteLine("File {0}", f.FullName);
            files.Add(f);                    
        }
    }
    catch
    {
        Console.WriteLine("Directory {0}  \n could not be accessed!!!!", dir.FullName);                
        return;  // We alredy got an error trying to access dir so dont try to access it again
    }

    // process each directory
    // If I have been able to see the files in the directory I should also be able 
    // to look at its directories so I dont think I should place this in a try catch block
    foreach (DirectoryInfo d in dir.GetDirectories())
    {
        folders.Add(d);
        FullDirList(d, searchPattern);                    
    }

}
 

En passant, j'ai eu ceci grâce à votre commentaire Jim Mischel

19voto

Darin Dimitrov Points 528142

Dans .NET 4.0, il existe une méthode Directory.EnumerateFiles qui renvoie un IEnumerable<string> et ne charge pas tous les fichiers en mémoire. Ce n'est que lorsque vous commencez à parcourir la collection renvoyée que les fichiers sont renvoyés et que les exceptions peuvent être gérées .

12voto

csharptest.net Points 16556

Il y a une longue histoire de l' .NET fichier énumération des méthodes de la lenteur. Le problème est, il n'est pas un instantané façon d'énumérer les grandes structures de répertoire. Même accepté de répondre ici a des problèmes de son avec GC allocations.

Le meilleur que j'ai pu faire est enveloppé dans ma bibliothèque et exposé comme le FileFile (source) de la classe dans le CSharpTest.Net.IO espace de noms. Cette classe peut énumérer les fichiers et dossiers inutiles sans GC allocations et de la chaîne de regroupement.

L'utilisation est assez simple, et la RaiseOnAccessDenied propriété d'ignorer les répertoires et fichiers que l'utilisateur n'a pas accès à:

    private static long SizeOf(string directory)
    {
        var fcounter = new CSharpTest.Net.IO.FindFile(directory, "*", true, true, true);
        fcounter.RaiseOnAccessDenied = false;

        long size = 0, total = 0;
        fcounter.FileFound +=
            (o, e) =>
            {
                if (!e.IsDirectory)
                {
                    Interlocked.Increment(ref total);
                    size += e.Length;
                }
            };

        Stopwatch sw = Stopwatch.StartNew();
        fcounter.Find();
        Console.WriteLine("Enumerated {0:n0} files totaling {1:n0} bytes in {2:n3} seconds.",
                          total, size, sw.Elapsed.TotalSeconds);
        return size;
    }

Pour mon local C:\ disque ce les sorties suivantes:

Énumérés 810,046 fichiers totalisant 307,707,792,662 octets dans 232.876 secondes.

Votre kilométrage peut varier en fonction de la vitesse du disque, mais c'est la méthode la plus rapide que j'ai trouvé de l'énumération des fichiers en code managé. Le paramètre d'événement est une mutation de classe de type FindFile.FileFoundEventArgs donc, assurez-vous de ne pas faire référence à elle comme il l'valeurs vont changer pour chaque événement a permis d'amasser.

2voto

Zombie Points 58

Vous pouvez l'utiliser pour obtenir tous les répertoires et sous-répertoires. Ensuite, il vous suffit de faire une boucle pour traiter les fichiers.

 string[] folders = System.IO.Directory.GetDirectories(@"C:\My Sample Path\","*", System.IO.SearchOption.AllDirectories);

foreach(string f in folders)
{
   //call some function to get all files in folder
}
 

2voto

TChadwick Points 290

Je sais que c'est vieux, mais ... Une autre option peut être d'utiliser FileSystemWatcher comme ceci:

 void SomeMethod()
{
    System.IO.FileSystemWatcher m_Watcher = new System.IO.FileSystemWatcher();
    m_Watcher.Path = path;
    m_Watcher.Filter = "*.*";
    m_Watcher.NotifyFilter = m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    m_Watcher.Created += new FileSystemEventHandler(OnChanged);
    m_Watcher.EnableRaisingEvents = true;
}

private void OnChanged(object sender, FileSystemEventArgs e)
    {
        string path = e.FullPath;

        lock (listLock)
        {
            pathsToUpload.Add(path);
        }
    }
 

Cela vous permettrait de surveiller les répertoires pour les modifications de fichiers avec un processus extrêmement léger, que vous pourriez ensuite utiliser pour stocker les noms des fichiers modifiés afin de pouvoir les sauvegarder au moment opportun.

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