80 votes

Quelle est la meilleure façon de calculer la taille d'un répertoire en .NET ?

J'ai écrit la routine suivante pour parcourir manuellement un répertoire et calculer sa taille en C#/.NET :

protected static float CalculateFolderSize(string folder)
{
    float folderSize = 0.0f;
    try
    {
        //Checks if the path is valid or not
        if (!Directory.Exists(folder))
            return folderSize;
        else
        {
            try
            {
                foreach (string file in Directory.GetFiles(folder))
                {
                    if (File.Exists(file))
                    {
                        FileInfo finfo = new FileInfo(file);
                        folderSize += finfo.Length;
                    }
                }

                foreach (string dir in Directory.GetDirectories(folder))
                    folderSize += CalculateFolderSize(dir);
            }
            catch (NotSupportedException e)
            {
                Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
            }
        }
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
    }
    return folderSize;
}

J'ai une application qui exécute cette routine de manière répétée pour un grand nombre de dossiers. Je me demande s'il existe un moyen plus efficace de calculer la taille d'un dossier avec .NET ? Je n'ai rien vu de spécifique dans le framework. Devrais-je utiliser P/Invoke et une API Win32 ? Quel est le moyen le plus efficace de calculer la taille d'un dossier avec .NET ?

75voto

Hao Lian Points 1518

Non, ça ressemble à la moyen recommandé pour calculer la taille de l'annuaire, la méthode pertinente est incluse ci-dessous :

public static long DirSize(DirectoryInfo d) 
{    
    long Size = 0;    
    // Add file sizes.
    FileInfo[] fis = d.GetFiles();
    foreach (FileInfo fi in fis) 
    {      
        Size += fi.Length;    
    }
    // Add subdirectory sizes.
    DirectoryInfo[] dis = d.GetDirectories();
    foreach (DirectoryInfo di in dis) 
    {
        Size += DirSize(di);   
    }
    return(Size);  
}

Vous appelleriez avec la Racine comme :

Console.WriteLine("The size is {1} bytes.", DirSize(new DirectoryInfo(targetFolder));

...où targetFolder est la taille du dossier à calculer.

0 votes

Recherchez "L'exemple de code suivant démontre comment calculer la taille d'un répertoire ;" et c'est le même que l'exemple ci-dessus.

1 votes

Lien actualisé en effet.

1 votes

@ladenedge lien mis à jour ? Celui-là vous amène à la v2.0 ... Le lien de la réponse est correct.

26voto

Mike Thompson Points 4178

Je ne pense pas qu'il existe une API Win32 permettant de calculer l'espace consommé par un répertoire, bien que je puisse être corrigé sur ce point. Si c'était le cas, je suppose qu'Explorer l'utiliserait. Si vous obtenez les propriétés d'un grand répertoire dans Explorer, le temps qu'il faut pour vous donner la taille du dossier est proportionnel au nombre de fichiers/sous-répertoires qu'il contient.

Votre routine semble assez ordonnée et simple. Gardez à l'esprit que vous calculez la somme des longueurs des fichiers, et non l'espace réel consommé sur le disque. L'espace consommé par l'espace gaspillé à la fin des clusters, des flux de fichiers, etc. est ignoré.

6 votes

Cette méthode ignore également les jonctions, les liens physiques, la compression et le stockage hors ligne.

0 votes

EnumerateFiles peut également être préférable, car certains dossiers peuvent contenir plus de 100 000 fichiers. Les jonctions, comme mentionné ci-dessus, peuvent provoquer une récursion infinie.

1 votes

Il existe une API. Le FileSystemObject (COM). Utilisez la méthodeGetFolder()-. msdn.microsoft.com/fr-us/library/f1xtf7ta(v=vs.84).aspx et la propriété Taille msdn.microsoft.com/fr/us/library/2d66skaf(v=vs.84).aspx

16voto

Grozz Points 3586
public static long DirSize(DirectoryInfo dir)
{
    return dir.GetFiles().Sum(fi => fi.Length) +
           dir.GetDirectories().Sum(di => DirSize(di));
}

1 votes

Cette solution présente plusieurs problèmes, l'un d'entre eux étant l'absence de terminaison pour les répertoires liés par des liens symboliques récursifs sur les partages NTFS (ou points de jonction) et Unix-SMB.

1 votes

Je suis d'accord. Quels sont les autres ?

2 votes

PathTooLongException (voir ce blogpost ) et des informations d'identification manquantes pour lire dans certains sous-répertoires ( UnauthorizedAccessException ) viennent à l'esprit. Un problème moins important est celui des lecteurs amovibles (clés USB, etc.) débranchés pendant le fonctionnement. La gestion des exceptions est indispensable - il suffit de renvoyer 0 localement et d'enregistrer l'erreur (ou les erreurs) si le résultat additionné a une quelconque valeur. BTW : Appliqué sur un partage distant, cela peut ressembler à une attaque DOS. Je suis sûr que j'ai oublié au moins un autre cas :-)

15voto

Mehrdad Points 70493

La vraie question est, à quoi comptez-vous utiliser la taille ?

Votre premièrement Le problème est qu'il y a au moins quatre définitions pour "taille du fichier" :

  • Le décalage de "fin de fichier", qui est le nombre d'octets que vous devez sauter pour aller du début à la fin du fichier.
    En d'autres termes, c'est le nombre d'octets logiquement dans le fichier (du point de vue de l'utilisation).

  • La "longueur des données valides", qui est égale à l'offset du premier octet. qui n'est pas réellement stocké .
    Elle est toujours inférieure ou égale à la "fin du fichier", et est un multiple de la taille du cluster.
    Par exemple, un fichier de 1 Go peut avoir une longueur de données valide de 1 Mo. Si vous demandez à Windows de lire les 8 premiers Mo, il lira les 1 premiers Mo et fera comme si le reste des données était là, en les retournant sous forme de zéros.

  • La "taille allouée" d'un fichier. Elle est toujours supérieure ou égale à la "fin du fichier".
    Il s'agit du nombre de clusters que le système d'exploitation a alloué au fichier, multiplié par la taille du cluster.
    Contrairement au cas où la "fin du fichier" est supérieure à la "longueur des données valides", les octets excédentaires sont pas considéré comme faisant partie des données du fichier, le système d'exploitation va donc pas remplir un tampon avec des zéros si vous essayez de lire dans la région allouée au-delà de la fin du fichier.

  • La "taille compressée" d'un fichier, qui n'est valable que pour les fichiers compressés (et épars ?).
    Elle est égale à la taille d'un cluster, multipliée par le nombre de clusters sur le volume qui sont effectivement alloué à ce fichier.
    Pour les fichiers non compressés et non épars, il n'y a pas de notion de "taille compressée" ; vous utiliseriez plutôt la "taille allouée".

Votre deuxième Le problème est qu'un "fichier" comme C:\Foo peut en fait avoir plusieurs ruisseaux de données.
Ce nom fait simplement référence à la par défaut flux. Un fichier peut avoir alternativement les flux, comme C:\Foo:Bar dont la taille n'est même pas affichée dans Explorer !

Votre troisième Le problème est qu'un "fichier" peut ont plusieurs noms ("hard links").
Par exemple, C:\Windows\notepad.exe et C:\Windows\System32\notepad.exe sont deux noms pour le même fichier. Tout peut être utilisé pour ouvrir tout le flux du fichier.

Votre quatrième Le problème est qu'un "fichier" (ou un répertoire) peut en fait ne pas être un fichier (ou un répertoire) :
Il pourrait s'agir d'un lien souple (un "lien symbolique" ou un "point de repérage") vers un autre fichier (ou répertoire).
Cet autre fichier n'est peut-être même pas sur le même disque. Il peut même pointer vers quelque chose sur le réseau, ou être récursif ! La taille doit-elle être infinie s'il est récursif ?

Votre cinquième est qu'il y a des pilotes "filtres" qui font que certains fichiers ou répertoires regardez comme des fichiers ou des répertoires réels, même s'ils ne le sont pas. Par exemple, les fichiers image WIM de Microsoft (qui sont compressés) peuvent être "montés" sur un dossier à l'aide d'un outil appelé ImageX, et ces fichiers WIM peuvent être "montés" sur un dossier. ne pas ressemblent à des points de repars ou à des liens. Ils ressemblent à des répertoires - sauf qu'ils ne sont pas vraiment des répertoires, et la notion de "taille" n'a pas vraiment de sens pour eux.

Votre sixième Le problème est que chaque fichier nécessite des métadonnées.
Par exemple, le fait d'avoir 10 noms pour le même fichier nécessite plus de métadonnées, ce qui requiert de l'espace. Si les noms de fichiers sont courts, avoir 10 noms peut être aussi économique que d'en avoir 1. S'ils sont longs, avoir plusieurs noms peut utiliser plus d'espace disque. pour les métadonnées . (Même histoire avec les flux multiples, etc.)
Vous les comptez aussi ?

2 votes

Je suis confus. Ce n'est pas une réponse, c'est une (assez longue) question, ou plusieurs questions.

4voto

Samuel Points 21085

C'est la meilleure façon de calculer la taille d'un répertoire. La seule autre méthode utilise toujours la récursion, mais elle est un peu plus facile à utiliser et n'est pas aussi flexible.

float folderSize = 0.0f;
FileInfo[] files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories);
foreach(FileInfo file in files) folderSize += file.Length;

4 votes

Le code affiché ne fonctionne pas, comme l'a également dit Joe. Vous devez utiliser DirectoryInfo pas Directory pour obtenir FileInfo réseau. L'énumération est également SearchOption pas SearchOptions .

0 votes

Vous pourriez utiliser Array.ConvertAll<string, FileInfo>(Directory.GetFiles(folder, "*", SearchOption.AllDirectories), x => new FileInfo(x));

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