Obtenez tous les fichiers et répertoires dans un chemin spécifique rapidement
je crée une application de sauvegarde où c# scanne un répertoire. Avant que j'utilise pour avoir quelque chose comme ceci afin d'obtenir tous les fichiers et les 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 pouvait pas être accédé et je reçois plusieurs erreurs. un exemple d'une erreur que je reçois est:
comme résultat j'ai créé une méthode récursive qui va scanner tous les fichiers dans le courant répertoire. S'il y a des répertoires dans ce répertoire, alors la méthode sera appelée à nouveau en passant ce répertoire. Ce qui est bien avec cette méthode, c'est que je pourrais placer les fichiers dans un bloc "try catch" me donnant l'option d'ajouter ces fichiers à une liste s'il n'y a pas d'erreurs et d'ajouter le répertoire à une autre liste si j'ai des erreurs.
try
{
files = di.GetFiles(searchPattern, SearchOption.TopDirectoryOnly);
}
catch
{
//info of this folder was not able to get
lstFilesErrors.Add(sDir(di));
return;
}
cette méthode fonctionne donc très bien.le seul problème est que lorsque je scanne un grand répertoire, cela prend beaucoup de temps. Comment pourrait - Je 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 ne reçois pas de fichiers.
7 réponses
Cette méthode est beaucoup plus rapide. Vous ne pouvez tel 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 quand il s'agit de traiter un grand nombre 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);
}
}
Par la façon dont je l'ai obtenu grâce à votre commentaire Jim Mischel
dans .NET 4.0 il y a le répertoire .EnumerateFiles méthode qui retourne un IEnumerable<string>
et ne charge pas tous les fichiers en mémoire. C'est seulement une fois que vous commencez à itérer sur la collection retournée que les fichiers seront retournés et exceptions pourraient être traitées .
les méthodes D'énumération des fichiers .NET sont lentes depuis longtemps. Le problème est qu'il n'y a pas de façon instantanée d'énumérer les grandes structures de répertoires. Même la réponse acceptée ici a ses problèmes avec les affectations du GC.
le mieux que j'ai pu faire est enveloppé dans ma bibliothèque et exposé comme le FindFile ( source ) classe dans le CSharpTest.Net.IO namespace. Cette classe peut énumérer des fichiers et des dossiers sans avoir besoin des attributions GC et de la formation de chaînes de caractères.
l'utilisation est assez simple, et la propriété RaiseOnAccessDenied sautera les répertoires et les fichiers auxquels 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:\ ce affiche ce qui suit:
a dénombré 810 046 fichiers totalisant 307 707 792 662 octets en 232,876 secondes.
votre kilométrage peut varier en fonction de la vitesse d'entraînement, mais c'est la méthode la plus rapide que j'ai trouvée pour énumérer les fichiers en code géré. Le paramètre event est une classe de mutation de type FindFile.FileFoundEventArgs alors assurez-vous de ne pas garder de référence car ses valeurs changeront pour chaque événement soulevé.
Vous pouvez l'utiliser pour obtenir tous les répertoires et sous-répertoires. Ensuite, bouclez simplement la 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
}
je sais que c'est vieux, mais... Une autre option peut être d'utiliser le FileSystemWatcher comme suit:
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 regarder les répertoires pour les changements de fichiers avec un processus extrêmement léger, que vous pourriez ensuite utiliser pour stocker les noms des fichiers qui ont changé afin que vous puissiez les Sauvegarder au moment approprié.
(copié de mon autre réponse dans votre autre question)
afficher le progrès lors de la recherche de tous les fichiers dans un répertoire
enumeration des fichiers Expres
bien sûr, comme vous le savez déjà, il ya beaucoup de façons de faire l'énumération... mais aucun ne sera instantané. Vous pouvez essayer d'utiliser le Journal USN du système de fichiers à faire scan. Jetez un coup d'oeil à ce projet dans CodePlex: MFT Scanner en VB.NET ... il a trouvé tous les fichiers dans mon lecteur IDE SATA (pas SSD) en moins de 15 secondes, et a trouvé 311000 fichiers.
vous aurez à filtrer les fichiers par chemin, de sorte que seuls les fichiers à l'intérieur du chemin que vous recherchez sont retournés. Mais c'est la partie facile du travail!
peut-être que ça vous aidera. Vous pouvez utiliser" DirectoryInfo.EnumerateFiles " méthode et manipuler Nonauthorizedaccessexception comme vous avez besoin.
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
DirectoryInfo diTop = new DirectoryInfo(@"d:\");
try
{
foreach (var fi in diTop.EnumerateFiles())
{
try
{
// Display each file over 10 MB;
if (fi.Length > 10000000)
{
Console.WriteLine("{0}\t\t{1}", fi.FullName, fi.Length.ToString("N0"));
}
}
catch (UnauthorizedAccessException UnAuthTop)
{
Console.WriteLine("{0}", UnAuthTop.Message);
}
}
foreach (var di in diTop.EnumerateDirectories("*"))
{
try
{
foreach (var fi in di.EnumerateFiles("*", SearchOption.AllDirectories))
{
try
{
// Display each file over 10 MB;
if (fi.Length > 10000000)
{
Console.WriteLine("{0}\t\t{1}", fi.FullName, fi.Length.ToString("N0"));
}
}
catch (UnauthorizedAccessException UnAuthFile)
{
Console.WriteLine("UnAuthFile: {0}", UnAuthFile.Message);
}
}
}
catch (UnauthorizedAccessException UnAuthSubDir)
{
Console.WriteLine("UnAuthSubDir: {0}", UnAuthSubDir.Message);
}
}
}
catch (DirectoryNotFoundException DirNotFound)
{
Console.WriteLine("{0}", DirNotFound.Message);
}
catch (UnauthorizedAccessException UnAuthDir)
{
Console.WriteLine("UnAuthDir: {0}", UnAuthDir.Message);
}
catch (PathTooLongException LongPath)
{
Console.WriteLine("{0}", LongPath.Message);
}
}
}