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 mit

    if(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?
    😃


Anmelden zum Antworten