Größe eines Ordners wird falsch ausgelesen



  • Nach längerer Abwesenheit brauche ich mal wieder den Rat des Forums.
    In meinem neusten Projekt, Software Informer mit Namen, welches vergleichbar mit dem Windows Internen Programm "Sofware" ist, das man unter der Systemsteurung findet, werden verschiedene Informationen zu den installierten Programmen auf dem PC gesammelt und in einer TListView ausgegeben. Unter anderem auch die Größe des zuvor ermittelten Installationsordners. Hier liegt nun auch mein Problem, bisher kümmert sich folgender Algorithmus um das Auslesen der einzelnen Dateien und das Zusammenrechnen der Gesamtgröße in Byte:

    float __fastcall TwndSys_informer::GetFolderSize(String cFolder)
    {
        WIN32_FIND_DATA wfdFile_info; //enthält Informationen über die Datei
        HANDLE hFile; //Handle auf die geöffnete Datei, respektive den geöffneten Ordner
        String cDirectory_buffer = cFolder + "*.*",cEnd_checksum = ""; //an Ordner wird Platzhalterzeichen für alle Dateien und Ordner eingesetzt
        float fTotal_folder_size = 0; //Gesamtgröße auf 0 Byte
        hFile = FindFirstFile(cDirectory_buffer.c_str(),&wfdFile_info); //Datei ".", Systemintern, zu vernachlässigen
        if(hFile != INVALID_HANDLE_VALUE) //wenn kein Fehler, Zugriff auf Ordner
        {
            FindNextFile(hFile,&wfdFile_info); //Datei "..", Systemintern, zu vernachlässigen
            cEnd_checksum = wfdFile_info.cFileName;
            FindNextFile(hFile,&wfdFile_info);
            if(hFile != INVALID_HANDLE_VALUE && cEnd_checksum != wfdFile_info.cFileName) //wenn kein Fehler, Zugriff auf Ordner
            {
                //Testdatei, zur Überprüfung ob Ordner Leer ist muss auch mitgerechnet werden
                if(wfdFile_info.nFileSizeLow <= MAXDWORD) //Datei kleiner als ca. 4 GB
                {
                    fTotal_folder_size += wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                }
                else //Datei größer als ca. 4GB
                {
                    fTotal_folder_size += (wfdFile_info.nFileSizeHigh * MAXDWORD) + wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                }
                //Schleifenbeginn
                while(cEnd_checksum != wfdFile_info.cFileName) //wenn Prüfstring mit Namen der neuen Datei übereinstimmt
                {                                              //Ende des Ordners erreicht, da letzte Datei wieder aufgerufen
                                                               //wurde
                    cEnd_checksum = wfdFile_info.cFileName; //Gleichsetzen um Überprüfung im Schleifenkopf zu gewährleisten
                    FindNextFile(hFile,&wfdFile_info); //nächste Datei, respektiver Ordner wird angesprochen
                    if(wfdFile_info.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) //ist ein Ordner
                    {
    
                        Application->ProcessMessages();
                        float fSize_buf = GetFolderSize(cFolder + String(wfdFile_info.cFileName) + "\\");
                        if(fSize_buf != -1)
                        {
                            fTotal_folder_size += fSize_buf;
                        }
                    }
                    else //ist eine Datei
                    {
                        if(wfdFile_info.nFileSizeLow <= MAXDWORD) //Datei kleiner als ca. 4 GB
                        {
                            fTotal_folder_size += wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                        }
                        else //Datei größer als ca. 4GB
                        {
                            fTotal_folder_size += (wfdFile_info.nFileSizeHigh * MAXDWORD) + wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                        }
                    }
    
                }
                FindClose(hFile); //Handle schließen / freigeben, da nicht mehr gebraucht (Ende des Suchlaufs durch den Ordner)
                return fTotal_folder_size; //Rückgabe und Umrechnung in MB mit Umrechnungszahl 1000
            }
            else
            {
                return -1; //Bei Fehler (Ordner nicht vorhanden, nicht zu öffnen) Rückgabe -1
            }
        }
        else
        {
            return -1; //Bei Fehler (Ordner nicht vorhanden, nicht zu öffnen) Rückgabe -1
        }
    }
    

    Ich hoffe es ist nicht allzuschwer zu durchschauen, da ich mit einer Art ungarischer Notation arbeite und aussagekräftige Namen gewählt habe. Außerdem ist der Code auch ausdokumentiert.

    Jedenfalls liegt mein Problem in der Funktionalität dieses Algorithmus. Er läuft ordnungsgemäß ab, berechnet auch eine Größe, nur ist diese total ungenau.
    Ich habe den Verdacht, dass einige Dateien nicht beachtet werden und damit auch nicht in die Gesamtgröße mit einfließen. Ich habe aber bereits vieles versucht und bin nicht darauf gekommen, was beim Suchlauf schiefgeht.
    Zum Vergleich:
    Windows Explorer : Ordnergröße: 5,67 GB
    Sofware Informer : Ordnergröße: 3,349 GB

    Ich hoffe jemand hat ne Idee.



  • Was soll denn das hier machen:

    //Testdatei, zur Überprüfung ob Ordner Leer ist muss auch mitgerechnet werden
                if(wfdFile_info.nFileSizeLow <= MAXDWORD) //Datei kleiner als ca. 4 GB
                {
                    fTotal_folder_size += wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                }
                else //Datei größer als ca. 4GB
                {
                    fTotal_folder_size += (wfdFile_info.nFileSizeHigh * MAXDWORD) + wfdFile_info.nFileSizeLow; //Addieren der Dateigröße
                }
    

    nFileSizeLow ist ein DWORD. Der else-Zweig wird niemals erreicht.

    float fTotal_folder_size;
    

    Wieso speicherst Du das nicht in einen long long?

    Hast Du den Unterschied zwischen 'Größe' und 'Größe auf dem Datenträger' berücksichtigt?



  • Ja die ist ähnlich groß, also der Explorer zeigt bei dem oben gegebenen Bsp. Ordner auch was um die 5,8 GB an. Also der Wert, den mein Algorithmus ermittelt ist um Längen zu klein, wie gesagt schätze ich er übergeht Dateien? Oder was könnte der Grund sein. Der Ordner mit dem ich teste ist übrigens Gothic II, nur zur Information.

    nFileSizeLow ist ein DWORD. Der else-Zweig wird niemals erreicht.

    Das was du ansprichst stimmt, war ein Logikfehler.

    Was wäre der Vorteil statt float, long long zu nehmen?



  • Kevinus schrieb:

    wie gesagt schätze ich er übergeht Dateien?

    Na dann zähl doch mal die erfassten Dateien in deiner Schleife mit, oder erstell gleich eine Liste und vergleich diese mit der Ausgabe des Betriebssystems.



  • Gute Idee, mir ist auch weiterhin aufgefallen, dass mein Programm bei kleinen Programmen zu viel Speicherplatz berechnet.



  • So das mit der Liste war eine tolle Idee, so ist mir aufgefallen, dass immer der erste Fund jedes Ordners nicht ordnungsgemäß verarbeitet wurde, im Falle von Gothic waren das nun eben die Ordner mit einer Größe von knapp einem GB. Der Algorithmus wurde nun angepasst, jetzt werden annährend die gleichen Werte bei mir, der Systemsteuerung, dem Explorer, FreeCommander und FolderSize, einem Tool für Ordnergrößen im Explorer, angezeigt. Jedes Programm weicht dabei aber etwas ab, dies scheint aber an der Umrechnung, der Auslesemethode und eventuell weiteren Faktoren zu liegen. Ich danke für eure Mithilfe und vor allem für den Denkanstoß von Jansen.

    PS:
    @witte Nochmal die Frage an dich, was bringt es mir long long zu benutzen, anstatt float. Zweitens, ich habe jetzt eine ordentliche Abfrage für Dateigrößen über 4GB, ohne deine Anmerkung, dass meine Bedingung immer true ist, wäre ich nie darauf gekommen dort etwas zu ändern, danke.



  • Kevinus schrieb:

    Jedes Programm weicht dabei aber etwas ab, dies scheint aber an der Umrechnung, der Auslesemethode und eventuell weiteren Faktoren zu liegen.

    Kevinus schrieb:

    @witte Nochmal die Frage an dich, was bringt es mir long long zu benutzen

    Willst Du den Wert nur schätzen oder genau angeben? Ein float hat nur 32b Speicherplatz. Er kann sicherlich große Werte aufnehmen (10^38 oder so), aber dann zu Kosten der Genauigkeit, er nimmt es dann mit den einen oder anderen KByte nicht mehr so genau. long long ist ein ganzahliger Wert mit 64b. Du würdest dann sowas wie wfdFile_info.nFileSizeHigh << 32 + wfdFile_info.nFileSizeLow rechnen. Auf das byte genau.
    Das andere Thema: Hast Du den Unterschied zwischen 'Größe' und 'Größe auf dem Datenträger' berücksichtigt?

    /Edit (wfdFile_info.nFileSizeHigh << 32) + wfdFile_info.nFileSizeLow



  • Wie berücksichtige ich diesen Unterschied?

    Jedoch ist es auch so, dass nicht nur meine Methode einen anderen Wert berechnet, jedes der aufgezählten Programme hat einen anderen.



  • Ich wollte nur anmerken, dass geklärt werden muss, was gezählt werden soll. Die Organisation der Ordner im Dateisystem benötigt ja auch Speicher. Schließlich muss ja irgendwo in diesem System vermerkt werden, was in einem Ordner alles drin ist, Benutzerrechte usw. Des weiteren wird ein Dateisystem ja sicherlich in Datenblöcken strukturiert sein, wie auch immer das spezifisch realisiert ist. Dadurch werden Überhänge entstehen, eine Datei benötigt beispielsweise nicht genau drei Blöcke sondern vllt 3 Blöcke und 40b vom vierten Block. Dann muss geklärt werden ob diese 40b zählen oder der gesamte, unvollständig gefüllte, aber belegte Block. Wenn diese Programme nun unterschiedliche Zählphilosophien verwenden entstehen unterschiedliche Größen.



  • Ja das stimmt, wenn man mit Rechts auf einen Ordner klickt sind ja auch beide Werte angegeben. Meine Größe bezieht sich, so glaube ich auf die tatsächliche Dateigröße der gesamten Dateien, nicht wie viel das Programm auf dem Datenträger belegt, denn ich zähle ja nur die Größen der Dateien, nicht z.B. der Ordner. Auch die Verwaltungsdaten zu Benutzerrechten etc. werden von mir nicht ausgelesen, demnach wohl auch nicht berücksichtigt.



  • hi
    das 1 kb = 1024 byte wird berücksichtigt?
    Nur son Gedanke

    wNw



  • Ja wird es.


Anmelden zum Antworten