Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++ Tiedostojen uudelleen nimeäminen

Sivun loppuun

Newb [21.01.2007 14:47:00]

#

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ää. ^^

Antti Laaksonen [21.01.2007 23:28:34]

#

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?

Newb [22.01.2007 19:23:47]

#

Ongelmana on enää se uuden nimen muodostus, tiedostojen nimien lukemisen tiedostosta onnistuin tekemään nyt soveltamalla tuota C-oppaassa olevaa esimerkkiä.

Metabolix [22.01.2007 19:48:52]

#

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ä.

sqwiik [22.01.2007 19:52:19]

#

Funktioiden replace & find luulisi olevan käyttökelpoisia tässä tapauksessa:

Replace
Find

string uusipaate(".jpg");
size_type alku = tiedostonimi.find(".txt", 0);
if(alku != string::npos){
  tiedostonimi.replace(alku, uusipaate.length(), uusipaate);
}

Newb [22.01.2007 21:34:46]

#

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ää?

Metabolix [22.01.2007 21:45:54]

#

string juttu;
rename(juttu.c_str(), ...);

Newb [23.01.2007 08:52:09]

#

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?

maka78 [23.01.2007 10:35:16]

#

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.

Newb [23.01.2007 16:11:22]

#

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ää?

Legu [23.01.2007 16:15:20]

#

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?

Newb [23.01.2007 16:22:52]

#

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");
    }

Legu [23.01.2007 16:59:01]

#

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;
}

Newb [23.01.2007 18:19:59]

#

Hei kiitti, nyt toimii! Tuli samalla opittua pari uutta funktiotakin.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta