Miten saan tietyn rivin luettua .txt-tiedostosta?
koodi siis avaa tiedoston: tiedosto = fopen("testi.txt", "r");
ja haluan lukea muuttujaan vaikka rivin 42.
fget avulla ei kai voi määrätä riviä.
Luet ensin 41 riviä "pois".
FILE tiedosto = fopen("testi.txt", "r"); int i=0; char kirjain; char rivi[80]; for( i<41 ) { kirjain = fgetc(tiedosto); if( kirjain==32 ) { i++; } } //nyt voit lukea 42:n rivin haluamallasi tavalla //esim: fgets(rivi, 80, tiedosto); //tukee max 80 merkin rivejä fclose(tiedosto);
eli siis fgetc lukee yhden rivin ja seuraavalla kerralla seuraavan?
EDIT mitä eroa on fgetc ja fgets funktioilla?
L2-K2 kirjoitti:
kirjain==32
Miksi 32? Sehän on väli. Miksei '\n'
?
Kuten hakukoneen avulla tai jopa L2-K2:n koodista selviää, fgetc lukee yhden merkin ja fgets monta merkkiä. Koska rivin pituutta ei ennalta tiedetä, pitää vain tyytyä lukemaan tiedostosta merkkejä rivinvaihtomerkkiin ('\n'
) asti ja lopettamaan, kun on luettu haluttu määrä rivinvaihtoja. Parempi vaihtoehto tuolle hassulle silmukalle on sopiva fscanf-formaatti:
// Luetaan rivi (ensin kaikkea paitsi \n, sitten vain yksi \n), ei tallenneta: fscanf(tiedosto, "%*[^\n]%*1[\n]");
Metabolix kirjoitti:
L2-K2 kirjoitti:
kirjain==32
Miksi 32? Sehän on väli. Miksei
'\n'
?
Hups.. piti tietenkin olla 10. Toistaalta tuo fscanf on muutenkin elegantimpi.
Tuosta voipi soveltaa, jos sattuu sopimaan tarkoitukseen. Tämä on kirjoiteltu töissä ilman kääntäjää, joten virheitä lienee ja niistä olisi kiva kuulla. Ideana on tehdä jokaisesta tiedostosta oma olio, jota voidaan hallita. Tähän voi kehitellä myös php:ä tuttua explode funktiota helpolla. Tiedosto formaatin tulee tukea erotinta, jonka mukaan rivit pätkitään.
#include <vector> #include <fstream> #include <string> using namespace std; class Tiedosto{ private: string nimi; /* Muuta c_str() funkkarilla ennen käyttöä */ int rivi_lkm: /* Sama kuin vektorin koko Rivit.size(); */ int rivi; /* Haettava rivi Annetaan Tiedosto olion Hae_rivi(int n) */ vector <string> Rivit; /* Tietojen tallennus */ public: Tiedosto(string n); /* Muodostin nimi parametrina */ string Hae_rivi(int n); /* Palauttaa parametrina saadun riviä */ void Lisaa_rivit(); /* Lisää annetusta tiedostosta rivit vektoriin */ }; Tiedosto::Tiedosto(string n){ nimi = n; } Tiedosto::Hae_rivi(int n){ if(n > rivi_lkm){/* Mikäli pyydetty rivi on suurempi kuin rivien määrä */ return "Tiedostossa " << nimi << " ei ole annettua riviä" << endl; } else if(n < 0){/* Rivi ei saa myöskään olla negatiivinen */ return "Annettu numero ei voi olla negatiivinen" << endl; } else{ /* Muutoin annetaan kyseinen rivi mukisematta */ return Rivit[n - 1]; /* n - 1 Niin voi käyttää huoletta indeksiä 1 ekaan.. */ } } void Tiedosto::Lisaa_rivit(){ string rivi; /* Alustetaan muuttujaa rivejä varten */ ifstream sisaan(nimi.c_str()); while(sisaan >> rivi){/* Kunnes ei ole enää mitään rivejä jäljellä */ Rivit.push_back(rivi); /* Survotaan vektoriin tietoa */ rivi = ""; /* Muistetaan nollata välillä */ } rivi_lkm = Rivit.size(); /* Päivitetään rivimäärä */ sisaan.close(); }
L2-K2 kirjoitti:
Luet ensin 41 riviä "pois".
FILE tiedosto = fopen("testi.txt", "r"); int i=0; char kirjain; char rivi[80]; for( i<41 ) { kirjain = fgetc(tiedosto); if( kirjain==32 ) { i++; } } //nyt voit lukea 42:n rivin haluamallasi tavalla //esim: fgets(rivi, 80, tiedosto); //tukee max 80 merkin rivejä fclose(tiedosto);
C++:sta kun on kyse, niin miksei käytettäisi getlineä?
#include <fstream> #include <string> using namespace std; int main() { string filu = "test.txt"; ifstream tiedosto(filu.c_str()); string rivi; int halutturivi = 42; for(int i = 0; i <= halutturivi ; ++i ) { getline(tiedosto, rivi); } tiedosto.close(); // nyt rivi-muuttujassa on haluttu rivi return 0; }
TsaTsaTsaa kirjoitti:
C++:sta kun on kyse, niin miksei käytettäisi getlineä?
Onko kyseessä C++ jos käytetään fopen()?
Ihme sähläämistä, kun ei osaa ilman kääntäjää, mutta nyt toimii oikein.
#include <vector> #include <fstream> #include <string> using namespace std; class Tiedosto{ private: string nimi; /* Muuta c_str() funkkarilla ennen käyttöä */ int rivi_lkm; /* Sama kuin vektorin koko Rivit.size(); */ int rivi; /* Haettava rivi Annetaan Tiedosto olion Hae_rivi(int n) */ vector <string> Rivit; /* Tietojen tallennus */ public: Tiedosto(string n); /* Muodostin nimi parametrina */ string Hae_rivi(int n); /* Palauttaa parametrina saadun riviä */ void Lisaa_rivit(); /* Lisää annetusta tiedostosta rivit vektoriin */ }; Tiedosto::Tiedosto(string n){ nimi = n; this -> Lisaa_rivit(); } string Tiedosto::Hae_rivi(int n){ string tmp = ""; if(n > (rivi_lkm - 1)){/* Mikäli pyydetty rivi on suurempi kuin rivien määrä */ tmp.append("Tiedostossa "); tmp.append(nimi); tmp.append(" ei ole annettua rivia "); return tmp; } else if(n < 0){/* Rivi ei saa myöskään olla negatiivinen */ tmp.append("Annettu numero ei voi olla negatiivinen"); return tmp; } else{ /* Muutoin annetaan kyseinen rivi mukisematta */ return Rivit[n - 1]; /* n - 1 Niin voi käyttää huoletta indeksiä 1 ekaan.. */ } } void Tiedosto::Lisaa_rivit(){ string rivi; /* Alustetaan muuttujaa rivejä varten */ ifstream sisaan(nimi.c_str()); while(sisaan){/* Kunnes ei ole enää mitään rivejä jäljellä */ getline(sisaan, rivi); Rivit.push_back(rivi); /* Survotaan vektoriin tietoa */ rivi = ""; /* Muistetaan nollata välillä */ } rivi_lkm = Rivit.size(); /* Päivitetään rivimäärä */ sisaan.close(); }
L2-K2 kirjoitti:
TsaTsaTsaa kirjoitti:
C++:sta kun on kyse, niin miksei käytettäisi getlineä?
Onko kyseessä C++ jos käytetään fopen()?
Ei, mutta kyseessä on C++ kun kysyjä on otsikoksi laittanut c++.
EDIT: Jaa niin aloitusviestissä oli fopen(), ookoo.
Kannattaisi myös noissa ratkaisuissa muistaa, että kun kerran riviä ei tarvita mihinkään, on aivan älytöntä lukea se muistiin jollain getlinen tyyppisellä — puhumattakaan Teuron ehdotuksesta, että luettaisiin kaikki muistiin (paitsi tietenkin jos niitä kaikkia tarvitaan vielä). Muutenkin Teuron luokassa olisi vielä parantamisen varaa.
C++:n streameilla oikea tapa ilman muistiin lukemista olisi ignore:
#include <limits> // Hypätään rivin yli virta.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Aihe on jo aika vanha, joten et voi enää vastata siihen.