Problem bei Verzeichnis auslesen
-
Hallo!
Ich wollte mit folgendem Code ein Verzeichnis auslesen:#include <dirent.h> #include <iostream> using namespace std; int main() { DIR *hdir; struct dirent *entry; hdir = opendir("."); do { entry = readdir(hdir); if (entry) { cout << entry->d_name << endl; } } while (entry); closedir(hdir); }Mein Problem ist, dass "." und ".." dabei auch ausgegeben werden.
Ich habe versucht, das ganze mitif(entry->d_name=="." || entry->d_name=="..")abzufangen, aber das funktioniert nicht.
Kann mir jemand helfen?
-
nur mal grob:
if(entry->d_name!="." && entry->d_name!="..")
-
Hallo,
d_name ist in dirent als char-Array deklariert. => Wenn du zwei Arrays mit Hilfe des bereits vorhandenen op== vergleichst, vergleichst du nicht deren Inhalt miteinander, sondern die beiden Adressen, welche natürlicherweise voneinander abweichen.Lösung: Um den Inhalt zweier char-Arrays vergleichen zu können, kannst du z.B. die bereits vorhandenen Funktionen aus string.h bzw. cstring benutzen: strncmp() bzw. strcmp().
Gruß, Caipi
-
Ich kann aber auch entry->d_name einem String zuweisen. Dann muss ich es doch
auch durch == mit einem String vergleichen können.
cout<<entry->d_name ergibt als Ausgabe doch auch "..", dann muss das doch,
wenn es mit ".." verglichen wird, true ergeben.
Aber ich guck mit die Compare-Methoden mal an.
-
Deine Argumentation ist ein wenig wirr. Um das mal zu klären.
Was verstehst du unter einem String?
- eine Variable vom Typ std::string
- eine Variable vom Typ char*
- ein Stringliteral "ddd"
Ersterem kannst du das zuweisen. Damit ist auch ein Vergleich möglich. Das liegt aber daran, dass operator= (für die Zuweisung) und operator== (Für den Test auf Gleichheit) von std::string so überladen sind, dass sie ein Argument vom Typ const char* akzeptiern.
Das trifft auf Variante 2 und 3 nicht zu. Das sind eben keine Klassen.
-
Dann kann ich die Ausgabe von entry->d_name einem std::string zuweisen,
und dann mit ".." und "." vergleichen.
Ich probier's einfach mal.
-
Das ganze liess sich auch mit einem static_cast<string>(entry->d_name)
machen. Warum ich da nicht gleich draufgekommen bin...
-
Mach sowas auf keinen Fall. Das erzeugt undefiniertes Verhalten. Erzeuge dir einen temporären String wenn es sein muß.
if( string(entry->d_name) == "..")
-
Oder nimm, wie dir Caipi schon gesagt hat strcmp( ). Ist IMHO schneller als eine temporäre Erstellung eines std::string und einem Aufruf von std::string::operator==( ).
Ich nehme 'mal an, dass du für Windows programmierst. Dir sollte klar sein, dass <dirent.h> Borland-Spezifisch ist (korrigiert mich, wenn ich falsch liege). Um mit allen Compilern für Windows mit installierter Platform-SDK compilierbar zu bleiben, verwendest du besser FindFirstFile( ) und FindNextFile( ) aus der <windows.h>:
#include <iostream> #include <cstring> #include <windows.h> using namespace std; int main( ) { WIN32_FIND_DATA w32fd; void *find_handle = FindFirstFile( ".\\*.*", &w32fd ); if( find_handle == INVALID_HANDLE_VALUE ) { cout << "Directory listing failed!" << endl; return EXIT_FAILURE; } do { if( strcmp( w32fd.cFileName, "." ) && strcmp( w32fd.cFileName, ".." ) ) { cout << w32fd.cFileName << endl; } } while( FindNextFile( find_handle, &w32fd ) ); }Greetz, Swordfish
-
Nein, ich programmiere unter Linux. dirent ist da bekannt.
Ich hab die static_casts jetzt weggemacht und string(entry->d_name)
geschrieben.
Ich hab mal gelesen, dass man für die explizite Typenumwandlung, die
casts verwenden soll, die wären besser.
Meine Absicht mit dem Verzeichnis lesen ist folgende.
Ich gebe einen zentralen Pfad an. In diesem Pfad befinden sich weitere
Ordner, die ich nacheinander öffnen will, und nach 3 Dateien durchsuchen will.
Eine mit ".bmb", eine mit ".mpg" und eine mit ".png" als Endung.
Die bmb-Datei will ich öffnen, die ist im Textformat. Anhand dieser Datei
erstell ich ein Objekt, dem ich die Daten aus der Datei übergebe. And das
Objekt soll auch der vollständige Dateiname der mpg- und png-Datei übergeben
werden, die jedoch ohne vollständige Pfadangabe, nur den Dateinamen.
Und dieses Objekt wird dann in einer STL-Liste gespeichert.
Ich habe dazu o. g. Listing ineinander verschachtelt. Zuerst wird der erste
Ordner des Basisverzeichnisses gelesen, dieser Name wird dann übergeben.
Dann wird das innere Verzeichnis gelesen, und festgestellt, ob sich da drin
die gewünschten Files befinden.bool BombDir::readBombDir() { AllBombsList->clear(); DIR *outerHdir,*innerHdir; struct dirent *outerEntry,*innerEntry; string Bombentry; unsigned int ListPos=0; //Read base directory outerHdir=opendir(BombPath.c_str()); do { outerEntry=readdir(outerHdir); if(outerEntry && string(outerEntry->d_name)!="." && string(outerEntry->d_name)!="..") { Bombentry=BombPath+"/"+outerEntry->d_name; //Read bombentry innerHdir=opendir(Bombentry.c_str()); do { innerEntry=readdir(innerHdir); //Overread dots and search for bmb-file if(innerEntry && string(innerEntry->d_name)!="." && string(innerEntry->d_name)!=".." && strstr(string(innerEntry->d_name).c_str(),".bmb")) { ListPos++; //Open bmb-file fstream BombFile; //Build path string BombFilePath=BombPath+"/"+outerEntry->d_name+"/"+innerEntry->d_name; string temp1; unsigned int temp2; BombFile.open(BombFilePath.c_str(),ios_base::in); if(BombFile) { //Create a temporary Bomb object Bomb* tempBomb=new Bomb; //Read data from file and set temporary bomb getline(BombFile,temp1); tempBomb->setBombId(temp1); getline(BombFile,temp1); tempBomb->setBombName(temp1); getline(BombFile,temp1); tempBomb->setBombColour(temp1); BombFile>>temp2; tempBomb->setBombSize(temp2); BombFile>>temp2; tempBomb->setBombRaiseTime(temp2); BombFile>>temp2; tempBomb->setBombClimbHeight(temp2); BombFile>>temp2; tempBomb->setBombExplodeTime(temp2); //Overread newline getline(BombFile,temp1); getline(BombFile,temp1); tempBomb->setBombPicture(temp1); getline(BombFile,temp1); tempBomb->setBombMovie(temp1); //Call function to add bomb entry AddBombEntry(tempBomb,ListPos); delete tempBomb; BombFile.close(); } } //Search for mpg if(innerEntry && string(innerEntry->d_name)!="." && string(innerEntry->d_name)!=".." && strstr(string(innerEntry->d_name).c_str(),".mpg")) { std::cout<<innerEntry->d_name<<"\n";//Wird noch verarbeitet } //Search for png if(innerEntry && string(innerEntry->d_name)!="." && string(innerEntry->d_name)!=".." && strstr(string(innerEntry->d_name).c_str(),".png")) { std::cout<<innerEntry->d_name<<"\n";//Wird noch verarbeitet } } while(innerEntry); closedir(innerHdir); } } while(outerEntry); closedir(outerHdir); } void BombDir::MoveIter(unsigned int _Pos) { Iter=AllBombsList->begin(); for(unsigned int PosCount=1;PosCount!=_Pos;PosCount++) { Iter++; } return; }Die unterste Methode soll den Iterator der Liste bewegen. Die hab ich
gekapselt, da ich sie in dieser Klasse noch öfter brauchen werde.
Die add-Methode usw. muss ich noch schreiben.Hier noch meine Deklaration, aber es ist noch nicht ganz fertig:
#include<dirent.h> #include<list> #include"bomb.h" typedef std::list<Bomb>BombDirList; class BombDir { public: BombDir(std::string _BombPath):BombPath(_BombPath) { AllBombsList=new BombDirList; } ~BombDir() { delete AllBombsList; } bool readBombDir(); // bool delBombDir(std::string _DirName); // list* getBombDir() private: BombDir() {} std::string BombPath; BombDirList* AllBombsList; BombDirList::iterator Iter; void MoveIter(unsigned int); };Ist vielleicht alles etwas unschön oder umständlich realisiert, aber wie
gesagt, ich bin noch Anfänger.
Ich krieg erst so nach und nach ein Bild davon, was mir in der Standard-
bibliothek so alles zur Verfügung steht.
Ich hab jetzt direkt schon ein grösseres Projekt angefangen, und in dieser
Zeit schon alles einigemale umgekrempelt, weil ich feststellen musste, dass
ich das Rad neu erfunden habe. An lebenden Objekten lernt man doch am besten,
oder etwa nicht?
