Wie lässt sich die Größe eines Verzeichnisses in .NET am besten berechnen?

78

Ich habe die folgende Routine geschrieben, um ein Verzeichnis manuell zu durchlaufen und seine Größe in C # /. NET zu berechnen:


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

Ich habe eine Anwendung, die diese Routine wiederholt für eine große Anzahl von Ordnern ausführt. Ich frage mich, ob es eine effizientere Möglichkeit gibt, die Größe eines Ordners mit .NET zu berechnen. Ich habe nichts Spezielles im Framework gesehen. Sollte ich P / Invoke und eine Win32-API verwenden? Wie lässt sich die Größe eines Ordners in .NET am effizientesten berechnen?

Steve Wranovsky
quelle

Antworten:

25

Ich glaube nicht, dass es eine Win32-API gibt, um den von einem Verzeichnis belegten Speicherplatz zu berechnen, obwohl ich diesbezüglich noch korrigiert werden muss. Wenn es das gäbe, würde ich davon ausgehen, dass der Explorer es verwenden würde. Wenn Sie die Eigenschaften eines großen Verzeichnisses im Explorer erhalten, ist die Zeit, die für die Angabe der Ordnergröße benötigt wird, proportional zur Anzahl der darin enthaltenen Dateien / Unterverzeichnisse.

Ihre Routine scheint ziemlich ordentlich und einfach. Denken Sie daran, dass Sie die Summe der Dateilängen berechnen, nicht den tatsächlich auf der Festplatte belegten Speicherplatz. Speicherplatz, der durch verschwendeten Speicherplatz am Ende von Clustern, Dateistreams usw. belegt wird, wird ignoriert.

Mike Thompson
quelle
6
Diese Methode ignoriert auch Junctions, Hardlinks, Komprimierung und Offline-Speicher.
Anton Tykhyy
EnumerateFiles ist möglicherweise auch vorzuziehen, da sich möglicherweise Ordner mit mehr als 100.000 Dateien befinden. Junctions wie oben erwähnt können eine unendliche Rekursion IIRC verursachen.
Nur ein weiterer Metaprogrammer
1
Es gibt eine API. Das FileSystemObject (COM). Verwenden Sie die GetFolder () - Methode msdn.microsoft.com/en-us/library/f1xtf7ta(v=vs.84).aspx und die Size-Eigenschaft msdn.microsoft.com/en-us/library/2d66skaf(v=vs .84) .aspx
Daniel Fisher Lennybacon
@ DanielFisherlennybacon wissen Sie, wie es implementiert wird? Does fso.GetFolder().SizeSchleife rekursiv DirSize()tut oder vielleicht verfolgt Windows Ordnergrößen? Welche Art von "Größe" gibt es zurück ?
JFS
Warum nicht diese 'GetDiskFreeSpaceEx'-Funktion verwenden? Link: msdn.microsoft.com/en-us/library/windows/desktop/…
Ori Nachum
65

Nein, dies scheint die empfohlene Methode zur Berechnung der Verzeichnisgröße zu sein, die unten beschriebene relevante Methode:

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

Sie würden mit der Wurzel anrufen als:

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

... wo targetFolderist die zu berechnende Ordnergröße.

hao
quelle
Suche nach "Das folgende Codebeispiel zeigt, wie die Größe eines Verzeichnisses berechnet wird." und es ist das gleiche wie im obigen Beispiel.
mbrownnyc
1
Aktualisierter Link , fwiw.
Beladung
1
@ladenedge aktualisierter Link? Dieser bringt Sie zu v2.0 ... Der Antwortlink ist korrekt.
Kzfabi
Übrigens: Der empfohlene Weglink enthält das Beispiel nicht mehr. Scheint, als ob MSDN aktualisiert wurde und dieser verloren gegangen ist.
Kzfabi
4
Verwenden Sie EnumerateFiles und EnumerateDirectories
Mauro Sampietro
33
DirectoryInfo dirInfo = new DirectoryInfo(@strDirPath);
long dirSize = await Task.Run(() => dirInfo.EnumerateFiles( "*", SearchOption.AllDirectories).Sum(file => file.Length));
Trikaldarshiii
quelle
Dies wird "UnauthorizedAccess Ausnahme" erhalten überprüfen Sie dies: stackoverflow.com/questions/8877516/…
Ahmed Sabry
@AhmedSabry: Was verstehst du von diesem Fehler?
Trikaldarshiii
Es braucht eine Erlaubnis auf diesem Weg
Ahmed Sabry
@AhmedSabry genau, deshalb ist dieser 1-Liner gut. Wenn alle Berechtigungen gut sind, großartig. Wenn nicht, schlägt dies fehl und Sie benötigen keinen speziellen benutzerdefinierten Versuch. Fang, Sie wissen, welches Problem Sie haben.
Ofer Zelig
Dies wird ausgelöst, wenn der vollständige Pfad eines Unterverzeichnisses zu lang wird
user2261015
15
public static long DirSize(DirectoryInfo dir)
{
    return dir.GetFiles().Sum(fi => fi.Length) +
           dir.GetDirectories().Sum(di => DirSize(di));
}
Grozz
quelle
1
Diese Lösung weist mehrere Probleme auf, unter anderem das Fehlen einer Terminierung für rekursiv verknüpfte Verzeichnisse auf NTFS- (auch als Junction Points bezeichnet) und Unix-SMB-Freigaben.
mbx
1
Genau. Was sind die anderen?
Grozz
2
PathTooLongException(siehe diesen Blogpost ) und fehlende Anmeldeinformationen zum Lesen aus bestimmten Unterverzeichnissen ( UnauthorizedAccessException) kommen in den Sinn. Ein weniger wichtiges Problem sollten Wechseldatenträger (USB-Sticks usw.) sein, die während des Betriebs vom Stromnetz getrennt werden. Die Ausnahmebehandlung ist hier ein Muss - geben Sie einfach lokal 0 zurück und protokollieren Sie die Fehler, wenn das summierte Ergebnis einen beliebigen Wert haben soll. Übrigens: Auf einer Remote-Freigabe kann es wie ein DOS-Angriff aussehen. Ich bin sicher, ich habe mindestens einen anderen Fall verpasst :-)
mbx
Beim Umgang mit diesen bekannten Ausnahmen bekomme ich immer noch eine StackOverflowExceptionfür größere Laufwerke.
mbx
2
Ich denke, in all diesen Fällen zu werfen ist akzeptabel und daher ist das Standardverhalten in Ordnung. StackOverflowExceptionist die einzige, die behandelt werden sollte, obwohl ich nicht glaube, dass es ohne rekursive Symlinks erreicht werden kann.
Grozz
14

Die eigentliche Frage ist, wofür Sie die Größe verwenden möchten.

Ihr erstes Problem ist, dass es mindestens vier Definitionen für "Dateigröße" gibt:

  • Der Offset "Dateiende", dh die Anzahl der Bytes, die Sie überspringen müssen, um vom Anfang bis zum Ende der Datei zu gelangen.
    Mit anderen Worten, es ist die Anzahl der logisch in der Datei enthaltenen Bytes (aus Sicht der Verwendung).

  • Die "gültige Datenlänge", die dem Offset des ersten Bytes entspricht, das nicht tatsächlich gespeichert ist .
    Dies ist immer kleiner oder gleich dem "Dateiende" und ein Vielfaches der Clustergröße.
    Beispielsweise kann eine 1-GB-Datei eine gültige Datenlänge von 1 MB haben. Wenn Sie Windows auffordern, die ersten 8 MB zu lesen, liest es die ersten 1 MB und gibt vor, dass der Rest der Daten vorhanden ist, und gibt sie als Nullen zurück.

  • Die "zugewiesene Größe" einer Datei. Dies ist immer größer oder gleich dem "Dateiende".
    Dies ist die Anzahl der Cluster, die das Betriebssystem für die Datei zugewiesen hat, multipliziert mit der Clustergröße.
    Im Gegensatz zu dem Fall, in dem das "Dateiende" größer als die "gültige Datenlänge" ist, werden die überschüssigen Bytes nicht als Teil der Dateidaten betrachtet, sodass das Betriebssystem beim Einlesen keinen Puffer mit Nullen füllt die zugewiesene Region hinter dem Ende der Datei.

  • Die "komprimierte Größe" einer Datei, die nur für komprimierte (und spärliche?) Dateien gilt. Dies
    entspricht der Größe eines Clusters, multipliziert mit der Anzahl der Cluster auf dem Volume, die dieser Datei tatsächlich zugeordnet sind .
    Für nicht komprimierte und nicht spärliche Dateien gibt es keine Vorstellung von "komprimierter Größe". Sie würden stattdessen die "zugewiesene Größe" verwenden.

Ihr zweites Problem ist, dass eine "Datei" wie C:\Footatsächlich mehrere Datenströme haben kann.
Dieser Name bezieht sich nur auf den Standard- Stream. Eine Datei kann alternative Streams haben, z. B. C:\Foo:Barderen Größe im Explorer nicht einmal angezeigt wird!

Ihr drittes Problem ist, dass eine "Datei" mehrere Namen haben kann ("harte Links").
Zum Beispiel C:\Windows\notepad.exeund C:\Windows\System32\notepad.exesind zwei Namen für dieselbe Datei. Jeder Name kann verwendet werden, um einen beliebigen Stream der Datei zu öffnen .

Ihr viertes Problem ist, dass eine "Datei" (oder ein Verzeichnis) möglicherweise nicht einmal eine Datei (oder ein Verzeichnis) ist:
Es kann sich um einen Softlink (einen "symbolischen Link" oder einen "Analysepunkt") zu einer anderen Datei handeln ( oder Verzeichnis).
Diese andere Datei befindet sich möglicherweise nicht einmal auf demselben Laufwerk. Es könnte sogar auf etwas im Netzwerk verweisen oder sogar rekursiv sein! Sollte die Größe unendlich sein, wenn sie rekursiv ist?

Ihr fünfter ist, dass es "Filter" -Treiber gibt, die bestimmte Dateien oder Verzeichnisse wie tatsächliche Dateien oder Verzeichnisse aussehen lassen, obwohl dies nicht der Fall ist. Beispielsweise können die WIM-Image-Dateien von Microsoft (die komprimiert sind) mit einem Tool namens ImageX in einem Ordner "gemountet" werden, und diese sehen nicht wie Analysepunkte oder Links aus. Sie sehen genauso aus wie Verzeichnisse - nur dass sie eigentlich keine Verzeichnisse sind und der Begriff "Größe" für sie keinen Sinn ergibt.

Ihr sechstes Problem ist, dass jede Datei Metadaten benötigt.
Wenn Sie beispielsweise 10 Namen für dieselbe Datei haben, sind mehr Metadaten erforderlich, was Speicherplatz erfordert. Wenn die Dateinamen kurz sind, sind 10 Namen möglicherweise genauso günstig wie 1 Name. Wenn sie lang sind, können mehrere Namen mehr Speicherplatz für die Metadaten beanspruchen . (Gleiche Geschichte mit mehreren Streams usw.)
Zählen Sie diese auch?

user541686
quelle
2
Ich bin verwirrt. Dies ist keine Antwort, es ist eine (ziemlich lange) Frage oder ein Vielfaches davon.
Ofer Zelig
9
var size = new DirectoryInfo("E:\\").GetDirectorySize();

und hier ist der Code hinter dieser Erweiterungsmethode

public static long GetDirectorySize(this System.IO.DirectoryInfo directoryInfo, bool recursive = true)
{
    var startDirectorySize = default(long);
    if (directoryInfo == null || !directoryInfo.Exists)
        return startDirectorySize; //Return 0 while Directory does not exist.

    //Add size of files in the Current Directory to main size.
    foreach (var fileInfo in directoryInfo.GetFiles())
        System.Threading.Interlocked.Add(ref startDirectorySize, fileInfo.Length);

    if (recursive) //Loop on Sub Direcotries in the Current Directory and Calculate it's files size.
        System.Threading.Tasks.Parallel.ForEach(directoryInfo.GetDirectories(), (subDirectory) =>
    System.Threading.Interlocked.Add(ref startDirectorySize, GetDirectorySize(subDirectory, recursive)));

    return startDirectorySize;  //Return full Size of this Directory.
}
Ahmed Sabry
quelle
1
Dieser Code läuft schneller als jede Antwort, die in meinem Fall EnumerateFiles () verwendet.
Rm558
6

Es scheint, dass die folgende Methode Ihre Aufgabe schneller ausführt als die rekursive Funktion:

long size = 0;
DirectoryInfo dir = new DirectoryInfo(folder);
foreach (FileInfo fi in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
   size += fi.Length;
}

Ein einfacher Konsolenanwendungstest zeigt, dass diese Schleife Dateien schneller als die rekursive Funktion summiert und dasselbe Ergebnis liefert. Und Sie möchten wahrscheinlich LINQ-Methoden (wie Sum ()) verwenden, um diesen Code zu verkürzen.

Konstantin K.
quelle
In meinen Tests mit einem Verzeichnis, das Quellcode und viele versteckte Dateien enthält (SVN-Verzeichnis), unterscheiden sich die Ergebnisse von denen, die vom Dateisystem-Explorer gemeldet wurden.
David Doumèche
1
wie immer "*"anstelle von "*.*"für Dateien ohne Erweiterung verwenden
Bernhard
5

Schneller! Fügen Sie die COM-Referenz "Windows Script Host Object ..." hinzu.

public double GetWSHFolderSize(string Fldr)
    {
        //Reference "Windows Script Host Object Model" on the COM tab.
        IWshRuntimeLibrary.FileSystemObject FSO = new     IWshRuntimeLibrary.FileSystemObject();
        double FldrSize = (double)FSO.GetFolder(Fldr).Size;
        Marshal.FinalReleaseComObject(FSO);
        return FldrSize;
    }
private void button1_Click(object sender, EventArgs e)
        {
            string folderPath = @"C:\Windows";
        Stopwatch sWatch = new Stopwatch();

        sWatch.Start();
        double sizeOfDir = GetWSHFolderSize(folderPath);
        sWatch.Stop();
        MessageBox.Show("Directory size in Bytes : " + sizeOfDir + ", Time: " + sWatch.ElapsedMilliseconds.ToString());
          }
Alex
quelle
OK gut. Aber es scheint, dass es die Dateigröße und nicht die tatsächliche Größe auf der Festplatte gibt (ich habe einen Fall, in dem die Größe 18154 Bytes und die Größe auf der Festplatte 163840 Bytes beträgt!)
NGI
5

Diese Lösung funktioniert sehr gut. Es werden alle Unterordner gesammelt:

Directory.GetFiles(@"MainFolderPath", "*", SearchOption.AllDirectories).Sum(t => (new FileInfo(t).Length));
Shai Segev
quelle
4

Ich habe bis vor kurzem mit VS2008 und LINQ herumgespielt und diese kompakte und kurze Methode funktioniert hervorragend für mich (Beispiel ist in VB.NET; erfordert natürlich LINQ / .NET FW 3.5+):

Dim size As Int64 = (From strFile In My.Computer.FileSystem.GetFiles(strFolder, _
              FileIO.SearchOption.SearchAllSubDirectories) _
              Select New System.IO.FileInfo(strFile).Length).Sum()

Es ist kurz, durchsucht Unterverzeichnisse und ist einfach zu verstehen, wenn Sie die LINQ-Syntax kennen. Mit dem dritten Parameter der Funktion .GetFiles können Sie sogar Platzhalter für die Suche nach bestimmten Dateien angeben.

Ich bin kein C # -Experte, aber Sie können den My-Namespace auf diese Weise auf C # hinzufügen .

Ich denke, diese Art, eine Ordnergröße zu erhalten, ist nicht nur kürzer und moderner als die auf Haos Link beschriebene , sondern verwendet im Grunde die gleiche Loop-of-FileInfo-Methode, die dort am Ende beschrieben wurde.

Rodolfo G.
quelle
C #: return Directory.GetFiles (Verzeichnis, "*", SearchOption.AllDirectories) .Sum (x => (double) (neues FileInfo (x) .Length));
Thomas nn
3
Dies ist nicht ideal, da es fehlschlägt, wenn einem Verzeichnis der Zugriff verweigert wird und diese Ausnahme nicht ignoriert werden kann.
Newman
4

Dies ist der beste Weg, um die Größe eines Verzeichnisses zu berechnen. Nur auf andere Weise wird die Rekursion noch verwendet, ist jedoch etwas einfacher zu verwenden und nicht so flexibel.

float folderSize = 0.0f;
FileInfo[] files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories);
foreach(FileInfo file in files) folderSize += file.Length;
Samuel
quelle
4
Der gepostete Code funktioniert nicht, wie Joe auch gesagt hat. Sie müssen DirectoryInfonicht verwenden Directory, um FileInfoArray zu erhalten . Auch die Aufzählung ist SearchOptionnicht SearchOptions.
Tony
Sie könnten verwendenArray.ConvertAll<string, FileInfo>(Directory.GetFiles(folder, "*", SearchOption.AllDirectories), x => new FileInfo(x));
PJRobot
4

Ich habe die Antwort von @ Hao mit demselben Zählprinzip erweitert, aber eine umfassendere Datenrückgabe unterstützt, sodass Sie die Größe, die rekursive Größe, die Verzeichnisanzahl und die rekursive Verzeichnisanzahl mit einer Tiefe von N Ebenen zurückerhalten.

public class DiskSizeUtil
{
    /// <summary>
    /// Calculate disk space usage under <paramref name="root"/>.  If <paramref name="levels"/> is provided, 
    /// then return subdirectory disk usages as well, up to <paramref name="levels"/> levels deep.
    /// If levels is not provided or is 0, return a list with a single element representing the
    /// directory specified by <paramref name="root"/>.
    /// </summary>
    /// <returns></returns>
    public static FolderSizeInfo GetDirectorySize(DirectoryInfo root, int levels = 0)
    {
        var currentDirectory = new FolderSizeInfo();

        // Add file sizes.
        FileInfo[] fis = root.GetFiles();
        currentDirectory.Size = 0;
        foreach (FileInfo fi in fis)
        {
            currentDirectory.Size += fi.Length;
        }

        // Add subdirectory sizes.
        DirectoryInfo[] dis = root.GetDirectories();

        currentDirectory.Path = root;
        currentDirectory.SizeWithChildren = currentDirectory.Size;
        currentDirectory.DirectoryCount = dis.Length;
        currentDirectory.DirectoryCountWithChildren = dis.Length;
        currentDirectory.FileCount = fis.Length;
        currentDirectory.FileCountWithChildren = fis.Length;

        if (levels >= 0)
            currentDirectory.Children = new List<FolderSizeInfo>();

        foreach (DirectoryInfo di in dis)
        {
            var dd = GetDirectorySize(di, levels - 1);
            if (levels >= 0)
                currentDirectory.Children.Add(dd);

            currentDirectory.SizeWithChildren += dd.SizeWithChildren;
            currentDirectory.DirectoryCountWithChildren += dd.DirectoryCountWithChildren;
            currentDirectory.FileCountWithChildren += dd.FileCountWithChildren;
        }

        return currentDirectory;
    }

    public class FolderSizeInfo
    {
        public DirectoryInfo Path { get; set; }
        public long SizeWithChildren { get; set; }
        public long Size { get; set; }
        public int DirectoryCount { get; set; }
        public int DirectoryCountWithChildren { get; set; }
        public int FileCount { get; set; }
        public int FileCountWithChildren { get; set; }
        public List<FolderSizeInfo> Children { get; set; }
    }
}
Scott Stafford
quelle
3
public static long GetDirSize(string path)
{
    try
    {
        return Directory.EnumerateFiles(path).Sum(x => new FileInfo(x).Length)  
            +
               Directory.EnumerateDirectories(path).Sum(x => GetDirSize(x));
    }
    catch
    {
        return 0L;
    }
}
Raz Megrelidze
quelle
2

Was den besten Algorithmus angeht, haben Sie wahrscheinlich das Richtige. Ich würde empfehlen, dass Sie die rekursive Funktion entwirren und einen eigenen Stapel verwenden (denken Sie daran, dass ein Stapelüberlauf das Ende der Welt in einer .Net 2.0+ -App ist, die Ausnahme kann IIRC nicht abgefangen werden).

Das Wichtigste ist, dass Sie es, wenn Sie es in irgendeiner Form einer Benutzeroberfläche verwenden, in einen Arbeitsthread einfügen, der dem Benutzeroberflächenthread Aktualisierungen signalisiert.

Jonathan C Dickinson
quelle
2

Eine Alternative zu Trikaldarshis Einzeilenlösung. (Es wird vermieden, FileInfo-Objekte erstellen zu müssen.)

long sizeInBytes = Directory.EnumerateFiles("{path}","*", SearchOption.AllDirectories).Sum(fileInfo => new FileInfo(fileInfo).Length);
James Wierzba
quelle
Die Variable fileInfo ist vom Typ string, nicht FileInfo.
user425678
2
Directory.GetFiles(@"C:\Users\AliBayat","*",SearchOption.AllDirectories)
.Select (d => new FileInfo(d))
.Select (d => new { Directory = d.DirectoryName,FileSize = d.Length} )
.ToLookup (d => d.Directory )
.Select (d => new { Directory = d.Key,TotalSizeInMB =Math.Round(d.Select (x =>x.FileSize)
.Sum () /Math.Pow(1024.0,2),2)})
.OrderByDescending (d => d.TotalSizeInMB).ToList();

Wenn Sie GetFilesmit SearchOption.AllDirectoriesaufrufen, wird der vollständige Name aller Dateien im subdirectoriesangegebenen Verzeichnis zurückgegeben. Das Betriebssystem gibt die Größe der Dateien in Byte an. Sie können die Größe der Datei über die Eigenschaft Length abrufen. Wenn Sie es durch 1024 dividieren, das auf die Potenz 2 erhöht wird, erhalten Sie die Größe der Datei in Megabyte. Da ein Verzeichnis / Ordner viele Dateien enthalten kann, wird d.Select(x => x.FileSize)eine Sammlung von Dateigrößen in Megabyte zurückgegeben. Der letzte Aufruf, um Sum()die Gesamtgröße der Dateien im angegebenen Verzeichnis zu ermitteln.

Update: Die filterMask = " . " Funktioniert nicht mit Dateien ohne Erweiterung

Ali Bayat
quelle
1

Der schnellste Weg, den ich gefunden habe, ist die Verwendung von EnumerateFiles mit SearchOption.AllDirectories. Diese Methode ermöglicht auch das Aktualisieren der Benutzeroberfläche, während die Dateien durchsucht und die Größe gezählt werden. Lange Pfadnamen verursachen keine Probleme, da nicht versucht wird, FileInfo oder DirectoryInfo für den langen Pfadnamen zu erstellen. Während der Aufzählung von Dateien, obwohl der Dateiname lang ist, verursachen die von den EnumerateFiles zurückgegebenen FileInfo keine Probleme, solange der Name des Startverzeichnisses nicht zu lang ist. Es gibt immer noch ein Problem mit UnauthorizedAccess.

    private void DirectoryCountEnumTest(string sourceDirName)
    {
        // Get the subdirectories for the specified directory.
        long dataSize = 0;
        long fileCount = 0;
        string prevText = richTextBox1.Text;

        if (Directory.Exists(sourceDirName))
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            foreach (FileInfo file in dir.EnumerateFiles("*", SearchOption.AllDirectories))
            {
                fileCount++;
                try
                {
                    dataSize += file.Length;
                    richTextBox1.Text = prevText + ("\nCounting size: " + dataSize.ToString());
                }
                catch (Exception e)
                {
                    richTextBox1.AppendText("\n" + e.Message);
                }
            }
            richTextBox1.AppendText("\n files:" + fileCount.ToString());
        }
    }
Marienkäfer
quelle
1

Diese .NET Core-Befehlszeilen-App berechnet hier die Verzeichnisgrößen für einen bestimmten Pfad:

https://github.com/garethrbrown/folder-size

Die Schlüsselmethode ist diese, bei der Unterverzeichnisse rekursiv überprüft werden, um eine Gesamtgröße zu erhalten.

private static long DirectorySize(SortDirection sortDirection, DirectoryInfo directoryInfo, DirectoryData directoryData)
{
        long directorySizeBytes = 0;

        // Add file sizes for current directory

        FileInfo[] fileInfos = directoryInfo.GetFiles();

        foreach (FileInfo fileInfo in fileInfos)
        {
            directorySizeBytes += fileInfo.Length;
        }

        directoryData.Name = directoryInfo.Name;

        directoryData.SizeBytes += directorySizeBytes;

        // Recursively add subdirectory sizes

        DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();

        foreach (DirectoryInfo di in subDirectories)
        {
            var subDirectoryData = new DirectoryData(sortDirection);

            directoryData.DirectoryDatas.Add(subDirectoryData);

            directorySizeBytes += DirectorySize(sortDirection, di, subDirectoryData);
        }

        directoryData.SizeBytes = directorySizeBytes;

        return directorySizeBytes;
    }
}
gb2d
quelle
1

Beispiel für mehrere Threads zur Berechnung der Verzeichnisgröße aus Microsoft Docs , was schneller wäre

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      long totalSize = 0;

      String[] args = Environment.GetCommandLineArgs();
      if (args.Length == 1) {
         Console.WriteLine("There are no command line arguments.");
         return;
      }
      if (! Directory.Exists(args[1])) {
         Console.WriteLine("The directory does not exist.");
         return;
      }

      String[] files = Directory.GetFiles(args[1]);
      Parallel.For(0, files.Length,
                   index => { FileInfo fi = new FileInfo(files[index]);
                              long size = fi.Length;
                              Interlocked.Add(ref totalSize, size);
                   } );
      Console.WriteLine("Directory '{0}':", args[1]);
      Console.WriteLine("{0:N0} files, {1:N0} bytes", files.Length, totalSize);
   }
}
// The example displaysoutput like the following:
//       Directory 'c:\windows\':
//       32 files, 6,587,222 bytes

In diesem Beispiel werden nur die Dateien im aktuellen Ordner berechnet. Wenn Sie also alle Dateien rekursiv berechnen möchten, können Sie die ändern

String[] files = Directory.GetFiles(args[1]);

zu

String[] files = Directory.GetFiles(args[1], "*", SearchOption.AllDirectories);

SLdragon
quelle
0

Ich versuche die Probe zu ändern (Alexandre Pepin und haos Antwort)

Wie es ist

    private long GetDirectorySize(string dirPath)
    {
        if (Directory.Exists(dirPath) == false)
        {
            return 0;
        }

        DirectoryInfo dirInfo = new DirectoryInfo(dirPath);

        long size = 0;

        // Add file sizes.
        FileInfo[] fis = dirInfo.GetFiles();
        foreach (FileInfo fi in fis)
        {
            size += fi.Length;
        }

        // Add subdirectory sizes.
        DirectoryInfo[] dis = dirInfo.GetDirectories();
        foreach (DirectoryInfo di in dis)
        {
            size += GetDirectorySize(di.FullName);
        }

        return size;
    }

Sein

    private long GetDirectorySize2(string dirPath)
    {
        if (Directory.Exists(dirPath) == false)
        {
            return 0;
        }

        DirectoryInfo dirInfo = new DirectoryInfo(dirPath);

        long size = 0;

        // Add file sizes.
        IEnumerable<FileInfo> fis = dirInfo.EnumerateFiles("*.*", SearchOption.AllDirectories);
        foreach (FileInfo fi in fis)
        {
            size += fi.Length;
        }

        return size;
    }

Endlich können Sie das Ergebnis überprüfen

        // ---------------------------------------------
        // size of directory
        using System.IO;

        string log1Path = @"D:\SampleDirPath1";
        string log2Path = @"D:\SampleDirPath2";
        string log1DirName = Path.GetDirectoryName(log1Path);
        string log2DirName = Path.GetDirectoryName(log2Path);
        long log1Size = GetDirectorySize(log1Path);
        long log2Size = GetDirectorySize(log2Path);
        long log1Size2 = GetDirectorySize2(log1Path);
        long log2Size2 = GetDirectorySize2(log2Path);

        Console.WriteLine($@"{log1DirName} Size: {SizeSuffix(log1Size)}, {SizeSuffix(log1Size2)}
        {log2DirName} Size: {SizeSuffix(log2Size)}, {SizeSuffix(log2Size2)}");

und dies ist die SizeSuffix-Funktion

    private static readonly string[] SizeSuffixes =
               { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    /// <summary>
    /// Size Display
    /// </summary>
    /// <param name="value">bytes 數值</param>
    /// <param name="decimalPlaces">小數位數</param>
    /// <returns></returns>
    public static string SizeSuffix(Int64 value, int decimalPlaces = 2)
    {
        if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
        if (value < 0) { return "-" + SizeSuffix(-value); }
        if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }

        // mag is 0 for bytes, 1 for KB, 2, for MB, etc.
        int mag = (int)Math.Log(value, 1024);

        // 1L << (mag * 10) == 2 ^ (10 * mag) 
        // [i.e. the number of bytes in the unit corresponding to mag]
        decimal adjustedSize = (decimal)value / (1L << (mag * 10));

        // make adjustment when the value is large enough that
        // it would round up to 1000 or more
        if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
        {
            mag += 1;
            adjustedSize /= 1024;
        }

        return string.Format("{0:n" + decimalPlaces + "} {1}",
            adjustedSize,
            SizeSuffixes[mag]);
    }
Ken Tseng
quelle
-3

Ich weiß, dass dies keine .net-Lösung ist, aber hier kommt es trotzdem. Vielleicht ist es praktisch für Leute, die Windows 10 haben und eine schnellere Lösung wollen. Wenn Sie diesen Befehl beispielsweise an Ihrer Eingabeaufforderung ausführen oder drücken Sie winKey + R:

bash -c "du -sh /mnt/c/Users/; sleep 5"    

So sleep 5haben Sie Zeit, um die Ergebnisse zu sehen, und das Fenster wird nicht geschlossen

Auf meinem Computer wird Folgendes angezeigt:

Geben Sie hier die Bildbeschreibung ein

Beachten Sie am Ende, wie 85G (85 Gigabyte) angezeigt werden. Es ist schnell im Vergleich zu .Net. Wenn Sie die Größe genauer sehen möchten, entfernen Sie die Größe, hdie für lesbar steht.

Also mach einfach so etwas. Processes.Start("bash",... arguments)Das ist nicht der genaue Code, aber du kommst auf die Idee.

Tono Nam
quelle