Dateioperation: Datei umbenennen



  • Hallo,

    ich weiß, daß es unhöflich ist, wenn man mit seinem ersten Post gleich eine Frage stellt, aber ich weiß im Moment nicht mehr, was da falsch sein könnte.

    Es geht um folgendes Programm:

    #include <cstdlib>
    #include <dirent.h>
    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        DIR *hdir;
        struct dirent *entry;
    
        hdir = opendir("./test");
        do
        {
            entry = readdir(hdir);
            if (entry)
            {
                cout << entry->d_name << endl;
                char a[entry->d_namlen],b[entry->d_namlen-4];
                for (int i=0;i<entry->d_namlen;i++)
                {
                    a[i]=entry->d_name[i];
                }
                for (int i=0;i<entry->d_namlen;i++)
                {
                    b[i]=entry->d_name[i+4];
                }
                for(int i=0;i<entry->d_namlen-4;i++)
                {
                        cout << b[i];
                }
                        cout << endl;
                rename(a,b); 
    
            }
        } while (entry);
        closedir(hdir);
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Der Sinn dahinter soll sein, daß dieses kleine Programm alle Dateien in dem Unterordner "test" umbenennen soll und dabei die ersten 4 Stellen wegläßt. Das Programm wird fehlerfrei kompiliert und ausgeführt, aber dennoch wird nichts umbenannt. Im Array b[] ist auch korrekt der gekürtzte Name drin.

    Was habe ich denn nun schon wieder falsch gemacht 😕

    Helft einem Anfänger - ach ja, ich nutze DevC, Windows XP.



  • Nimm lieber strcpy(), um die Dateinamen zu kopieren - im Gegensatz zu deinem Code kümmert sich das nämlich um die korrekte Darstellung von C-Strings (Stichwort: Null-Terminator).

    Und wo wir gerade beim Thema Null-Terminator sind - für den mußt du auch noch Speicherplatz bereitstellen.

    PS: Du könntest dir viel Arbeit sparen, wenn du statt der VLA's (die ANSI-C++ sowieso nicht unterstützt) std::string verwenden würdest.



  • Oh, ich muss gestehen, daß ich von Deinem Posting nur Bahnhof verstanden habe 😞

    Ich bin wirklich noch ein ziemlicher Anfänger. Wärest Du so nett und tätest es mir ein wenig erklären (wenn Du genug Zeit hast)



  • Erstens: C-String sind einfache char-Arrays, wobei das Zeichen '\0' (auch bekannt als "Null-Terminator") kennzeichnet, wo der String zu Ende ist. Bei deinen Kopier-Schleifen überträgst du zwar den Text-Inhalt aus dem Dateinamen, aber nicht den Null-Terminator - das bewirkt, daß das Programm nach den eigentlichen Dateinamen noch weitere Nonsens-Zeichen im Speicher sucht, bis es zufällig über ein 0-Byte stolpert.

    Zweitens: Du kopierst auch noch mehr Zeichen in das Array 'b', als du dort Platz reserviert hast - damit überschreibst du eventuell Speicherplatz, den du woanders benötigst.

    Drittens: VLAs (Variable Length Arrays - Arrays mit dynamischer Größe) gibt es zwar im C99-Standard, aber nicht bei C++. Da bedeutet, daß ein vernünftiger C++-Compiler die Deklaration von a und b verbieten sollte. Und anstelle der char-Arrays solltest du sowieso std::string verwenden.

    Zusammenfassend:

    #include <cstdlib>
    #include <dirent.h>
    #include <iostream>
    #include <string>  //für std::string
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        DIR *hdir;
        struct dirent *entry;
    
        hdir = opendir("./test");
        do
        {
            entry = readdir(hdir);
            if (entry)
            {
                cout << entry->d_name << endl;
                //char a[entry->d_namlen],b[entry->d_namlen-4];
                string a,b;
                /*for (int i=0;i<entry->d_namlen;i++)
                {
                    a[i]=entry->d_name[i];
                }*/
                a = entry->d_name;
                /*for (int i=0;i<entry->d_namlen;i++)
                {
                    b[i]=entry->d_name[i+4];
                }*/
                b = entry->d_name+4;
                /*for(int i=0;i<entry->d_namlen-4;i++)
                {
                        cout << b[i];
                }*/
                cout << b << endl;
                rename(a.c_str(),b.c_str()); 
            }
        } while (entry);
        closedir(hdir);
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    


  • Danke für die Erklärungen, aber wenn ich es richtig verstehe (bitte nicht schlagen, wenn nicht), dann tut dieses Programm nun nicht mehr das, was ich ursprunglich wollte.

    Ich wollte ein Dateinamen einlesen, und dann die ersten 4 Zeichen weglassen und die Datei danach umbenennen.

    Ich glaube ich habe noch sehr viel zu lernen...



  • Dragosani schrieb:

    Danke für die Erklärungen, aber wenn ich es richtig verstehe (bitte nicht schlagen, wenn nicht), dann tut dieses Programm nun nicht mehr das, was ich ursprunglich wollte.

    Wieso sollte es denn etwas anderes tun? 'a' enthält den ursprünglichen Dateinamen, 'b' den Namen ohne die ersten vier Zeichen (das 'entry->d_name**+4**' ist Zeiger-Arithmetik und liefert die Position des fünften Zeichens) - und durch den rename()-Aufruf wird die Datei a in b umgenannt.

    *grübelt* ich bin mir nur nicht sicher, ob d_name den kompletten Pfad enthält - wenn ja, ist aber schon dein ursprünglicher Entwurf zum Scheitern verurteilt (weil du vom Pfad nur das "C:\x" abschneidest).



  • Oh .. nochmals danke, ich werde es gleich mal ausprobieren.

    @d_name: der enthält nur den Dateinamen (habe ich geprüft), also kein Problem 🙂

    Edit: Hm, habe das Programm mal kompiliert und laufen lassen: es tut leider genau das selbe wie meines: die Anzeige auf dem Bildschirm stimmt, aber umbenannt wird nichts 😞

    Edit2: JAAAAAAAAAAA, es fehlte natürlich ein chdir("./test");. Nun geht es! Daaaaanke, ich hoffe, ich nerve nicht mehr zu oft mit dummen Fragen 🙂



  • hi ihr,
    das programm von Dragosani fand ich recht interessant.
    ich hab es um zwei/drei kleinigkeiten erweitert.

    #include <cstdlib>
    #include <dirent.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char **argv)
    {
        DIR *dir;
        struct dirent *entry;
        int zlvv = 0; // Zeichen löschen von vorne;
    
        cout << "Eingabe der zu loeschenden Zeichen (von vorne): ";
        cin >> zlvv;
    
        if((dir=opendir(argv[1])) == NULL)
        {
          cout << "Fehler bei opendir ...\n";
          return EXIT_FAILURE;
        }
        chdir(argv[1]);
        do
        {
            entry = readdir(dir);
            if (entry)
            {
                string dn_alt, dn_neu;
                dn_alt = entry->d_name;            
                dn_neu = entry->d_name + zlvv;
                cout << dn_alt << endl;
                cout << dn_neu << endl;
                rename(dn_alt.c_str(), dn_neu.c_str());
            }
        } while (entry);
    
        closedir(dir);
        system("pause");
        system("cls");
        return EXIT_SUCCESS; 
    }
    

    jetzt wollte ich es noch so machen das auch eine bestimmte anzahl zeichen von hinten abgeschnitten wird (exklusive der endung). leider funktioniert nichts von dem was ich versucht habe, evtl. reicht mein wissen dafür auch nicht aus.
    hoffentlich kann mich einer auf den richtigen weg schupsen :).

    mfg Dennis



  • Versuch's mal mit erase():

    size_t dotpos = dn_neu.find_last_of('.');
    size_t delpos = (dotpos!=string::npos)?(dotpos-delsize):(dn_neu.size()-delsize);
    dn_neu.erase(delpos,delsize);
    


  • vielen dank für den tip. es funktioniert
    hat leider etwas länger gedauert 🙂



  • Dragosani schrieb:

    ich weiß, daß es unhöflich ist, wenn man mit seinem ersten Post gleich eine Frage stellt

    LOL, woher hast Du denn diesen Mist? Wieso sollte das unhöflich sein? Das ist hier doch kein Konversationsclub.


Log in to reply