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

B

Buba235

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #1

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

D

deepthroat

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #2

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:

B

Buba235

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #3

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;

D

deepthroat

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #4

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ß

B

Buba235

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #5

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!

D

deepthroat

Erfahrenes Mitglied
  • 11. Dezember 2008
  • #6

Hi.

Buba235 hat gesagt.:

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()

Buba235 hat gesagt.:

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.

Buba235 hat gesagt.:

Code:

 } else // not a dir { sPath.chop(1); sPath.append(FindFileData.cFileName);

Auch hier veränderst du wieder sPath. Den brauchst du doch noch.

Buba235 hat gesagt.:

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ß

B

Buba235

Erfahrenes Mitglied
  • 12. Dezember 2008
  • #7

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:

D

deepthroat

Erfahrenes Mitglied
  • 12. Dezember 2008
  • #8

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:

B

Buba235

Erfahrenes Mitglied
  • 12. Dezember 2008
  • #9

Super! Ich danke dir vielmals!

Es klappt soweit, dass ich ab jetzt weiter machen kann. Danke nochmal!

Um antworten zu können musst du eingeloggt sein.

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

References

Top Articles
Latest Posts
Article information

Author: Kareem Mueller DO

Last Updated:

Views: 6008

Rating: 4.6 / 5 (46 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Kareem Mueller DO

Birthday: 1997-01-04

Address: Apt. 156 12935 Runolfsdottir Mission, Greenfort, MN 74384-6749

Phone: +16704982844747

Job: Corporate Administration Planner

Hobby: Mountain biking, Jewelry making, Stone skipping, Lacemaking, Knife making, Scrapbooking, Letterboxing

Introduction: My name is Kareem Mueller DO, I am a vivacious, super, thoughtful, excited, handsome, beautiful, combative person who loves writing and wants to share my knowledge and understanding with you.