[C++] Problem beim (rekursiven) löschen von Ordnern und Dateien

Buba235

Erfahrenes Mitglied
Hallo Leute!

ICh steh grad ziemlich aufm Schlauch. Ich möchte einen bestimmten Pfad, der mir übergeben wird, komplett löschen. Ich muss ja erst den 1ten Ordner durchsuchen und falls da was drin ist,in den nächsten Ordner gehen usw. bis ich alles löschen kann. Mein Problem ist nun, dass ich die Rekursion nicht hinbekomme. Es muss an einer Kleinigkeit liegen. Das ganze Gerüst steht bereits, nur weiß ich nicht womit ich die Rekursion aufrufen muss. Soll heißen, ich weiß nicht was die Parameter sein sollen. Hier mal mein Code:

Code:
bool UaFileEngineWin::rmdir(const UaUniString &dirName) const
{
    // Variables
    int                 iErg            = 0; 
    bool                bRet;
    UaUniStringList     list;
    UaUniString         temp;
    UaUniString         sNewPath;
    HANDLE              hFind;
    WIN32_FIND_DATA     FindFileData;

    // change sep from '\\' to '/' 
    UaDir myDir("");
    UaUniString         sPath           = myDir.fromNativeSeparators(dirName);
    UaUniString         tmp             = sPath;
    const UaUShort      *usTmp          = tmp.toUtf16();


    // check if path exists - if not return false
    if (exists(sPath) == true)
    {
        // Find first file in this dir
        hFind = FindFirstFile(sPath.toUtf16(), &FindFileData);
        if (hFind == INVALID_HANDLE_VALUE) 
        {
            //OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            return OpcUa_False;
        }
        else
        {
            // are there any files in the directory?
            if (FindNextFile(hFind, &FindFileData) != OpcUa_False) 
            {
                // remove all files to clean the directory
                while (FindNextFile(hFind, &FindFileData) != OpcUa_False)
                {
                    if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
                    {
                        // delete directory
                        iErg = _wrmdir(sPath.toUtf16());
                        if (iErg != 0)
                        {
                            return OpcUa_False;
                        }
                    }
                    else // not a dir
                    {
                    }
                }
            }
            else // => empty directory
            {
                // remove all empty directories
                while (FindNextFile(hFind, &FindFileData) == OpcUa_False)
                {
                    list = tmp.split("/");

                    // get the splitted path without separators and create new path
                    for (OpcUa_UInt16 i = 0; i < list.size(); i++)
                    {
                        temp        =   list[i];
                        sNewPath    +=  temp.append("/");

                        // check if first part of the path is the device
                        if (sNewPath == "C:/")
                        {
                            temp        =   list[i + 1];
                            sNewPath    +=  temp.append("/");
                        }

                        // check if this path exists - if not create it
                        if (exists(sNewPath) != OpcUa_False)
                        {

                            Hier muss die Rekursion rein!!

                            // delete directory
                            iErg = _wrmdir(sNewPath.toUtf16());
                            if (iErg != 0)
                            {
                                return OpcUa_False;
                            }
                        }
                    }
                }
            }

            // clean up
            FindClose(hFind);
        }
    }
    else // nothing to do
    {
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "UaDir::rmpath: Path doesn`t exist!\n");
        bRet = OpcUa_False;
    }

    return bRet;
}

Könnt ih mir da mal bitte von meinem "Kabel" runterhelfen?

Gruß Buba
 
Hi.

Warum verwendest du denn nicht eine Bibliothek wie z.B. Boost Filesystem, die dir das ganze abnimmt; du müßtest das Rad nicht nochmal neu erfinden...

FindFileData.dwFileAttributes enthält Bitflags. D.h. du solltest prüfen ob das FILE_ATTRIBUTE_DIRECTORY Flag gesetzt ist, und nicht ob dwFileAttributes exakt damit übereinstimmt.

Du mußt Wildcards verwenden um alle Einträge in einem Verzeichnis zu finden.

Die Rekursion funktioniert so:
Code:
bool delete_recursive(path) {
  foreach(file in path + "/*") {
    if (file == "." || file == "..") continue;

    if (IS_DIR(file)) {
       delete_recursive(file);   
    } else {
       remove(file);
    }
  }
  remove(path);
}
Gruß
 
Zuletzt bearbeitet:
Hallo!

Leider darf und kann ich Boost nicht verwenden. Ebenso kann/darf ich SHGetFileOperation (oder so ähnlich) nicht verwenden. Leider Aber ich hab auch schon einiges weiter geschafft. Nur bekomm ich jetzt bei meiner neuen Version immer (nach dem ersten rekursiven Aufruf) ein ungültiges Handle, obwohl der Pfad existiert. Hier mal mein Code:

Code:
    // Variables
    int                 iErg            = 0; 
    bool                bRet;
    UaUniStringList     list;
    UaUniString         temp;
    UaUniString         sNewPath;
    UaUniString         sNameToRemove;
    HANDLE              hFind;
    WIN32_FIND_DATA     FindFileData;


    // change sep from '\\' to '/' 
    UaDir myDir("");
    UaUniString         sPath           = myDir.fromNativeSeparators(dirName);
    UaUniString         tmp             = sPath;
    const UaUShort      *usTmp          = tmp.toUtf16();


    // check if path exists - if not return false
    if (exists(sPath) == true)
    {
        // Find first file in this dir
        hFind = FindFirstFile(sPath.toUtf16(), &FindFileData); <- hier wirds ungültig obwohl der Pfad passt!
        if (hFind == INVALID_HANDLE_VALUE) 
        {
            //OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            return OpcUa_False;
        }
        else
        {
            // remove all files to clean the directory
            while (FindNextFile(hFind, &FindFileData) == OpcUa_False)
            {
                if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    // delete directory
                    iErg = _wrmdir(sPath.toUtf16());
                    if (iErg != 0)
                    {
                        return false;
                    }

                    list = tmp.split("/");

                    // get the splitted path without separators and create new path
                    for (OpcUa_UInt16 i = 0; i < list.size(); i++)
                    {
                        temp = list[i];
                        
                        if (temp == FindFileData.cFileName)
                        {
                            break;
                        }

                        sNewPath += temp.append("/");
                    }

                    // call recursively
                    rmdir(sNewPath);
                    
                }
                else // not a dir
                {
                    DeleteFile(FindFileData.cFileName);
                }
            }

            // clean up
            FindClose(hFind);
        }
    }
    else // nothing to do
    {
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "UaDir::rmpath: Path doesn`t exist!\n");
        bRet = OpcUa_False;
    }

    return bRet;
 
Hi.

Du kannst das Verzeichnis doch nicht entfernen, bevor du dessen Inhalt rekursiv gelöscht hast.

Außerdem heißt es in der MSDN, das der Pfad für FindFirstFile keinen Backslash am Ende haben darf. Ich denke mal das gleiche gilt für einen Slash.

Und wie bereits gesagt, mußt du einen Wildcard an den Pfad anhängen.

Gruß
 
Hallo!

Leider bekomm ich es nicht hin! Ich bin entweder zu dämlich oder ich seh den Wald vor lauter Bäumen nicht.

Code:
    // Variables
    int                 iErg            = 0; 
    bool                bRet;
    UaUniStringList     list;
    UaUniString         temp;
    UaUniString         sNewPath;
    UaUniString         sNameToRemove;
    HANDLE              hFind;
    WIN32_FIND_DATA     FindFileData;


    // change sep from '\\' to '/' 
    UaDir myDir("");
    UaUniString         sPath           = myDir.fromNativeSeparators(dirName);
    UaUniString         tmp             = sPath;
    const UaUShort      *usTmp          = tmp.toUtf16();


    // check if path exists - if not return false
    if (exists(sPath) == true)
    {
        sPath.append("/*");
        // Find first file in this dir
        hFind = FindFirstFile(sPath.toUtf16(), &FindFileData);
        if (hFind == INVALID_HANDLE_VALUE) 
        {
            //OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
            return OpcUa_False;
        }
        else
        {
            
            // remove all files to clean the directory
            while (FindNextFile(hFind, &FindFileData) != 0)
            {

                if (FindFileData.dwFileAttributes == (DWORD)"." || FindFileData.dwFileAttributes == (DWORD)"..")
                {
                    continue;
                }

                if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    sPath.chop(2);
                    // call recursively
                    rmdir(sPath);
                }
                else // not a dir
                {
                    sPath.chop(1);
                    sPath.append(FindFileData.cFileName);
                    DeleteFile(sPath.toUtf16()); //FindFileData.cFileName);
                    printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
                }
            }

            // clean up
            FindClose(hFind);
        }
    }
    else // nothing to do
    {
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "UaDir::rmpath: Path doesn`t exist!\n");
        bRet = OpcUa_False;
    }

    return bRet;

Bei dieser Version rutscht er mir in eine Endlosschleife weil er aus der rekursion nicht raus kommt!
 
Hi.
Code:
    // check if path exists - if not return false
    if (exists(sPath) == true)
    {
        sPath.append("/*");
Ich würde an dieser Stelle den sPath nicht modifizieren. Unterstützt denn deine UaUniString Klasse keine Konkatenation a la:
C++:
(sPath + "/*").toUtf16()
Code:
                if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    sPath.chop(2);
                    // call recursively
                    rmdir(sPath);
Wenn du hier chop aufrufst, wird dein Pfad immer kürzer. Außerdem ist es Quatsch die Funktion nochmal mit dem gleichen Parameter aufzurufen den sie gerade bekommen hat. Du mußt hier
C++:
rmdir(sPath + "/" + FindFileData.cFileName);
aufrufen.
Code:
                }
                else // not a dir
                {
                    sPath.chop(1);
                    sPath.append(FindFileData.cFileName);
Auch hier veränderst du wieder sPath. Den brauchst du doch noch.
Code:
            // clean up
            FindClose(hFind);
Hier fehlt nun noch der Aufruf von RemoveDirectory. Außerdem solltest du noch prüfen ob nach der Schleife der Fehler ERROR_NO_MORE_FILES war (und du solltest die "." und ".." Einträge überspringen). Außerdem überspringst du immer den ersten gefunden Eintrag. Es ist nicht festgelegt, das dies immer "." ist.
C++:
do {
   ...
} while (FindNextFile(...) != 0);
DWORD error = GetLastError();
FindClose(...);

if (error != ERROR_NO_MORE_FILES) {
  // Fehler...
} else {
  RemoveDirectory(sPath);
}
Gruß
 
Hallo!

Ich hab mich an deine Anweisungen gehalten, aber ich bekomms nicht hin. Irgendwie kann ich die "." und ".." nicht ausschließen. Er rennt mir immer über diese Abfrage drüber, als wärs nichts. Ich kanns dir mal zeigen:

Code:
    // Find first file in this dir
    hFind = FindFirstFile(sPath.toUtf16(), &FindFileData);
    if (hFind == INVALID_HANDLE_VALUE) 
    {
        //OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
        printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
        return OpcUa_False;
    }
    else
    {
        // remove all files to clean the directory
        while (FindNextFile(hFind, &FindFileData) != 0)
        {
            if (FindFileData.cFileName == L"." || FindFileData.cFileName == L"..")
            {
                continue;
            }
            else
            {
                if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    sPath.chop(2);
                    sPath.append("/");
                    sPath.append(FindFileData.cFileName);

                    // call recursively
                    rmdir(sPath);
                }
                else // not a dir
                {
                    DeleteFile(sPath.toUtf16()); 
                    printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
                }
            }
        }

        // error reporting
        DWORD dwError = GetLastError();

        // clean up
        FindClose(hFind);

        if (dwError != ERROR_NO_MORE_FILES)
        {
            printf("UaDir::rmpath: Invalid File Handle. GetLastError reports %d\n", GetLastError());
        }
        else
        {
            iErg = _wrmdir(sPath.toUtf16());
            if (iErg != 0)
            {
                return OpcUa_False;
            }
        }
    }

    return bRet;

Außerdem hab ich die Überprüfung ob der Pfad existiert rausgezogen und bei einem Aufruf davor eingestellt. Das hat sonst große Probleme verursacht. Zu dem DeleteFile komm ich also gar nicht. Wenn ich aber da rein kommen sollte, dann ist klar dass ich den Pfad noch abändern muss. Aber das Hauptproblem besteht darin, dass ich einfach in eine Endlosschleife laufe, weil er die "." und ".." einfach ignoriert und kein continue macht!
 
Zuletzt bearbeitet:
Hi.

Du kannst C-Strings doch nicht einfach mit dem == Operator vergleichen. Da vergleichst du nur die Zeiger (die auf jeden Fall nicht gleich sein werden).

Hier mal zum Abschreiben, du mußt nur deine Datentypen verwenden:
C:
int delete(LPCTSTR dir) {
   WIN32_FIND_DATA ffd;
   TCHAR szDir[MAX_PATH];
   HANDLE hFind = INVALID_HANDLE_VALUE;
   DWORD dwError=0;

   _tcscpy(szDir, dir);
   _tcscat(szDir, TEXT("/*"));

   // Find the first file in the directory.

   hFind = FindFirstFile(szDir, &ffd);

   if (INVALID_HANDLE_VALUE == hFind) 
   {
      // Fehler ... 
      return dwError;
   } 
   
   // delete all the files and directories in the directory recursively...

   do
   {
	   if (_tcscmp(ffd.cFileName, TEXT(".")) == 0 || _tcscmp(ffd.cFileName, TEXT("..")) == 0) continue;

	   TCHAR absPath[MAX_PATH];
	   _tcscpy(absPath, dir);
	   _tcscat(absPath, TEXT("/"));
	   _tcscat(absPath, ffd.cFileName);

	   if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
	   {
		   int err = delete(absPath);
		   if (err != ERROR_SUCCESS) {
		       // abort...
		       FindClose(hFind);
		       return err;
		   }
	   }
	   else
	   {
		   if (!DeleteFile(absPath)) {
		       FindClose(hFind);
		       return GetLastError();
		   }
	   }
   } while (FindNextFile(hFind, &ffd) != 0);
 
   dwError = GetLastError();
   FindClose(hFind);
   if (dwError != ERROR_NO_MORE_FILES) 
   {
      // Fehler...
   } else {
	   if (!RemoveDirectory(dir)) {
               dwError = GetLastError();
	   }
   }

   return dwError;
}
Gruß
 
Zuletzt bearbeitet:
Zurück