C++ Dateisuche verbrauch viel zu viel RAM?

5 Antworten

Da es sich hierbei um eine Rekursive Funktion handelt braucht der Code auch entsprechend RAM je tiefer die Ordner verschachtelt sind.

Mit einer iterativen Funktion könnte man Ram sparen aber die ist eben komplexer zu schreiben.

Das liegt an der nötigen Rekursionstiefe um die komplette Verzeichnisstruktur abzubilden. (FunFact: Wen es irgendwo Hardlinks gibt, die auf Verzeichnisse weiter oben in der Struktur verweisen geht der Speicherbedarf gegen unendlich bzw. bis zum Crash.)

Als iterative Funktion brauchts nur einen Bruchteil des RAMs:

#include <Windows.h>
#include <iostream>
#include <stack>

void FindAllFiles(std::string folderName) {
    WIN32_FIND_DATA FileData;
    std::stack<std::string> dirs;
    dirs.push(folderName);
    std::string curdir;
    while(dirs.size() > 0){
        curdir = dirs.top();
        dirs.pop();
        if(curdir.back() != '\\') curdir.append("\\");
        HANDLE FirstFile = FindFirstFileA((curdir + "*").c_str(), &FileData);
        if (FirstFile != INVALID_HANDLE_VALUE) {
            while (FindNextFileA(FirstFile, &FileData)) {
                if (strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0) {
                    if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                        dirs.push(curdir+FileData.cFileName);
                    }
                    else {
                        std::cout << curdir + FileData.cFileName << "\n";
                    }
                }
            }
            CloseHandle(FirstFile);
        }
    }
}

int main(void){
    FindAllFiles("C:\\");
}

Der Code:

#include <Windows.h>

#include <iostream>

void FindAllFiles(std::string folderName)

{   

   WIN32_FIND_DATA FileData;

   std::string folderNameWithSt(folderName + "*"), NewPath, Output;

   HANDLE FirstFile = FindFirstFileA(folderNameWithSt.c_str(), &FileData);

   if (FirstFile != INVALID_HANDLE_VALUE)

   {

       while (FindNextFileA(FirstFile, &FileData))

       {

           if (strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0)

           {

               if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)

               {

                   NewPath = (folderName + FileData.cFileName) + "\\";

                   FindAllFiles(NewPath);

                   if (!FirstFile)

                       CloseHandle(FirstFile);

               }

               else

               {

                   std::cout << folderName + FileData.cFileName << "\n";

                   if (!FirstFile)

                       CloseHandle(FirstFile);

               }

           }

       }

   }

   return;

}

int main(void)

{

   FindAllFiles("C:\\");

}

Der Code (von HelgaDieWaldfee) ist suboptimal...

  • innerhalb der while-Schleife wird FirstFile nie verändert, !FirstFile kann nie wahr werden, das FindNext ändert das Handle nicht
  • Dafür fehlt hinter der while-Schleife (aber im if) ein FindClose(FirstFile) um den Speicher wieder freizugeben, ob CloseHande stattdessen auch alles freigibt weiss ich nicht, das müsste aber dann eben auch dahin. Im Moment wird der Speicher nie wieder freigegeben.
  • FindFirstFileA liefert direkt den ersten Eintrag, den du ignorierst... mache lieber eine do .. while Schleife statt der while-Schleife mit dem FindNext am Ende statt dem while... Das fällt wahrscheinlich nur im \ auf, da der erste Eintrag in einem Unterverzeichnis "." sein dürfte, den du eh ignorierst
Woher ich das weiß:Berufserfahrung – Softwareentwickler & Admin
Erst habe ich es mit dem "std::filesystem::recursive_directory_iterator" probiert, der crasht aber immer an einer Stelle.

Leider sagst Du nichts genaueres, aber:

If the directory structure contains cycles, the end iterator may be unreachable.

Zyklen wären ein mögliches Problem.

Wenn das Durchsuchen eines Baumes 1GB RAM benötigt, dann werden unnötige Daten vorgehalten oder es besteht ein Speicherleck.