Mitenköhän onnistuisi tehdä ohjelma, jolla voi uudelleen nimetä kaikki kansiossa olevat tiedostot toiseksi, esim. test.txt -> test.jpg?
Yksittäisen tiedoston saan muutettua rename-funktiolla, mutta kaikkien tiedostojen nimeämisestä ei tuu mitään.
Yksi keino, mikä tuli mieleen, oli tehdä listaus kansion tiedostoista tekstitiedostoon, josta ohjelma lukee tiedostojen nimet ja muuttaa sitten. En vain onnistu lukemaan tiedostossa olevia nimiä ja muuttamaan niitä *.jpg päätteisiksi.
Vähän epäselvästi selitetty, mutta koittakaa ymmärtää. ^^
Hakemiston tiedostojen nimet voi hakea ohjelmaan suoraan, mutta toiminnon toteutus riippuu käyttöjärjestelmästä. Esimerkiksi Windowsissa voi käyttää funktioita FindFirstFile ja FindNextFile, joista löytyy tietoa haulla. Jos tiedostojen nimet ovat valmiina tiedostossa, ohjelman tekeminen kyllä helpottuu.
Minkä säännön mukaan ohjelman pitäisi muuttaa tiedostojen nimiä? Onko juuri uuden nimen muodostus se ohjelman osa, jota et ole onnistunut tekemään, vai onko vaikeutena hakemiston tiedostojen nimien lukeminen tiedostosta?
Ongelmana on enää se uuden nimen muodostus, tiedostojen nimien lukemisen tiedostosta onnistuin tekemään nyt soveltamalla tuota C-oppaassa olevaa esimerkkiä.
Kopioi nimi toiseen tekstimuuttujaan (strcpy
) ja vaihda viimeiset kirjaimet (strlen(nimi)-1
on viimeinen).
char nimi[1024], uusi_nimi[1024]; int i; strcpy(uusi_nimi, nimi); i = strlen(nimi); uusi_nimi[i-3] = 'j'; uusi_nimi[i-2] = 'p'; uusi_nimi[i-1] = 'g'; // Teksti päättyy nollamerkkiin (0 tai [t]'\0'[/t]), eli jos uusi nimi ei ole yhtä pitkä kuin vanha, täytyy loppuun laittaa sellainen. Tässä tapauksessa se ei ole tarpeen, kun se on kopioitu jo vanhasta nimestä, mutta halutessasi voisit laittaa tiedoston päätteeksi jpgq: uusi_nimi[i] = 'q'; // Ylimääräinen kirjain uusi_nimi[i+1] = 0; // Lopetusmerkki on yhtä myöhemmin kuin ennen
Ilmeisesti siis käytit C:tä. C++:lla ja string-luokalla homma toimii toisin. Lisäyksenä vielä, että sqwiik kertoo alla aivan oikein, mutta find_last_of taitaa olla parempi etsintäväline päätettä etsittäessä.
Funktioiden replace & find luulisi olevan käyttökelpoisia tässä tapauksessa:
string uusipaate(".jpg"); size_type alku = tiedostonimi.find(".txt", 0); if(alku != string::npos){ tiedostonimi.replace(alku, uusipaate.length(), uusipaate); }
Kielenä on C++ niin kuin otsikko kertoo ja kääntäjänä Dev-C++. En saanut kumpaakaan esimerkkiä toimimaan. Sain kuitenkin itse tehtyä sen osan, joka vaihtaa päätteen .jpg:ksi. Yksi ongelma tosin tuli rename-funktiota käytettäessä. Koodi on ehkä vähän syvältä..
FILE *tied; char rivi[30]; tied = fopen("testi.txt", "r"); if (tied != NULL) { while (!feof(tied)) { fgets(rivi, 30, tied); printf("%s", rivi); } fclose(tied); } else { printf("Virhe!\n"); } int i; i = strlen(("%s", rivi)); string uusinimi=("%s", rivi); uusinimi.replace(i -4, i, ".jpg"); rename(("%s", rivi), uusinimi);
Ja virhekoodi: "cannot convert `std::string' to `const char*' for argument `2' to `int rename(const char*, const char*)'" rename-funktion kohdalta. Mitenköhän tuo pitäisi pistää?
string juttu; rename(juttu.c_str(), ...);
Kiitti, nyt toimii hyvin. Tosin nyt vasta tajusin, että tuota koodia käyttäen se muuttaakin vain tiedoston viimeisellä rivillä olevan nimen. Mitenköhän sen saisi korjattua, en ainakaan Ohjelmointiputkan C++-oppaan avulla onnistunut sitä tekemään?
No jos mietit vähän tuota ohjelma rakennetta. Ja mietit etenkin mitä tuossa while loopissa tapahtuu. Ja missä vaiheessa sitten vaihdat tuon nimen sinne tiedostoon, niin periaatteessa pitäisi valjeta myös ratkaisu.
fgets(rivi, 30, tied);
Tuossahan se lukee tiedostosta aina seur. rivin, joten eikö sen rename-funktion pitäisi tulla tuon jälkeen sen printf(); tilalle? Eipä toiminut niin. Oonko ihan hukassa vai mikä mättää?
Newb kirjoitti:
... en ainakaan Ohjelmointiputkan C++-oppaan avulla onnistunut sitä tekemään?
Ihan vaan tiedoksi, Ohjelmointiputkassa ei ole C++ opasta, vain C-opas.
Newb kirjoitti:
... eikö sen rename-funktion pitäisi tulla tuon jälkeen sen printf(); tilalle?
Siihen se tulee. Minkäs näköinen se koodi nyt sitten on, jos ei tuossa kohdassa toimi?
Legu kirjoitti:
Newb kirjoitti:
... en ainakaan Ohjelmointiputkan C++-oppaan avulla onnistunut sitä tekemään?
Ihan vaan tiedoksi, Ohjelmointiputkassa ei ole C++ opasta, vain C-opas.
Tosiaan, C-opashan se on.
Legu kirjoitti:
Newb kirjoitti:
... eikö sen rename-funktion pitäisi tulla tuon jälkeen sen printf(); tilalle?
Siihen se tulee. Minkäs näköinen se koodi nyt sitten on, jos ei tuossa kohdassa toimi?
int i; FILE *tied; char rivi[30]; tied = fopen("testi.txt", "r"); if (tied != NULL) { while (!feof(tied)) { fgets(rivi, 30, tied); i = strlen(("%s", rivi)); string uusinimi=("%s", rivi); uusinimi.replace(i -4, i, ".jpg"); rename( ("%s", rivi) , uusinimi.c_str() ); } fclose(tied); } else { printf("Virhe!\n"); }
Kun teet kerran C++:alla, niin kannattaisi varmaan käyttää STL:ää (C++ standardikirjasto). Tässä miten homma toimisi:
//Sisällyttetään otsikkotiedostot #include <iostream> #include <string> #include <fstream> //Kerrotaan kääntäjälle, että käytetään std-nimiavaruutta (ettei tarvitse jokaisen eteen std::) using namespace std; int main(int argc, char * argv[]) { string rivi; string uusinimi; //avataan tiedostot.txt ifstream tiedostolista ("tiedostot.txt"); if (tiedostolista.is_open()) { //Jos aukesi, niin mennään tiedosto läpi rivi riviltä while (!tiedostolista.eof()) { //Otetaan yksi rivi getline (tiedostolista, rivi); //Kopioidaan -> "uusinimi" uusinimi = rivi; //Pisteen paikka string::size_type piste; //Etsitään viimeinen piste piste = uusinimi.find_last_of("."); //Jos löytyi, poistetaan kaikki pisteestä eteenpäin if (piste != string::npos) uusinimi.erase(piste); //Lisätään perään ".jpg" uusinimi.append(".jpg"); //Vaihdetaan nimi rename(rivi.c_str(), uusinimi.c_str()); } //Suljetaan tiedosto tiedostolista.close(); } else { //Ei saatu auki, tulostetaan virhe cout << "Virhe! :(" << endl; } return 0; }
Sillä pitäisi homma hoitua. Tällä toimii myös erikoisemmatkin tapaukset;
testi.txt -> testi.jpg testi.testaus -> testi.jpg testi -> testi.jpg testi.testaus.txt -> testi.testaus.jpg
Tuohon voi toki lisätä virheentarkistuksen (vaihtuiko nimi todella)
if (rename(...) == 0) { cout << "Nimi vaihtui!" << endl; } else { cout << "Uudelleennimeämisessä tapahtui virhe!" << endl; }
Hei kiitti, nyt toimii! Tuli samalla opittua pari uutta funktiotakin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.