Tiedostokysely

Yleistä

C++:ssa tiedostoja pystytään käsittelemään standardin mukaisesti fstream-kirjaston avulla. Tiedoston käsittely tapahtuu joko teksti- tai binäärimuodossa. Tekstimuodossa olevaa tietoa voidaan helposti käsitellä editorilla, kun taas binäärimuotoinen tieto on sisäisen esitystavan mukaista eikä ole näin luettavassa muodossa.

Tiedostoja käsitellään tiedosto-olion avulla. Tiedosto-olion luokka sisältää metodit, joiden avulla tiedostoja on mahdollista käsitellä. Tiedostonkäsittely luokkia ovat seuraavat kolme luokkaa:

Tiedosto-olion luonti ja fyysinen tiedoston avaus ovat eri tapahtumia, jotka on mahdollista kirjoittaa ohjelmassa yhteen tai erikseen.

Yhteen:

ifstream tdsto("tdsto.dat");

Erikseen:

ifstream tdsto;
tdsto.open("tdsto.dat");

Virtoihin kirjoittaminen ja lukeminen onnistuvat <<- ja >>-operaattoreilla kuten näyttöä käsiteltäessä. Tiedosto-oliot ovat olioita siinä missä muutkin oliot. Tiedosto-olioita voidaan siis viedä parametreina kuten mitä tahansa muita olioita.

Järjestelmä etsii tiedostoa yleensä samasta hakemistosta kuin missä ohjelma sijaitsee. Ohjelmassa voidaan kuitenkin määrätä tiedoston tarkka sijainti, esim. "c:\\alihak\\tdsto.txt". Tallennettavaa tai luettavaa tiedostoa ei siis tarvitse, eikä saa, liittää projektiin.

Tiedoston avaamista, lukemista ja tallentamista ei ole pakko tehdä muodostajassa/tuhoajassa. Lataamiselle ja tallentamiselle on hyödyllistä tehdä omat funktionsa, joita voidaan kutsua tarpeen mukaan.

Tiedostosta etsiminen ei eroa merkkijonosta etsimisestä. getline-funktiolla luetusta merkkijonosta voidaan etsiä tietoa kuten tavallisesta merkkijonosta.

Tiedoston loppumisen havaitseminen

Totuusarvotyyppinen metodi eof palauttaa tosi, kun ollaan tiedoston lopun kohdalla. Arvo on tosi vasta kun kuvitteellisen loppumerkin kohdalle on saavuttu, ei silloin kun se on seuraavana. Peek-metodi palauttaa seuraavana lukemisvuorossa olevan merkin. Tiedoston lukemisen loppuminen voidaan siis testata esimerkiksi seuraavasti:

while(tdsto.peek() != EOF) tai kurssilla usein käytetyllä rivin lukevalla tavalla:

while(getline(tdsto,rivi))

Kyseiset metodit ovat standardin mukaisia.

Miten saan selville tiedoston koon?

Tiedoston koon tavuina saa selville helposti esimerkiksi io.h:sta löytyvällä epästandardilla, ainoastaan Win32:ssa toimivalla, metodilla

long filelenght(int kahva).

Kahva tiedostoon saadaan tehtyä seuraavasti:

int kahva = open("tdsto.dat",0);

Tiedoston kopiointi, haku ja hakemistorakenteen käyttö

Näihin toimintoihin ei ole olemassa standardin mukaista ratkaisua. Seuraavassa esitellään joitakin epästandardeja tapoja tiedostojen käsittelyyn.

Käyttöjärjestelmälle pystyy tekemään kutsuja stdlib.h:sta löytyvällä komennolla system. Seuraava käsky esimerkiksi tulostaa hakemiston sisällön:

system("dir");

Tiedostojen kopioinnit yms. onnistuvat siis suoraan DOS-komennoilla. system -käsky toimii sekä Win32- että Unix-ympäristöissä.

Vaihtoehtoisesti tiedoston käsittelyyn sopivia funktiota löytyy myös dirent.h-kirjastosta. Kirjaston sisältöön voi tutustua täältä. Kirjasto toimii sekä Win32:ssa että Unix:ssa.

Hakemistojen käsittely on riippuvaista käytetystä käyttöjärjestelmästä ja kääntäjästä. Win32-ympäristölle löytyy sopiva kirjasto dir.h. Seuraava koodinpätkä esittelee tiedostojen etsimisen tulostamalla C-aseman juuressa olevat tiedostot. Ohjelmassa luodaan tietue fblock, joka sisältää tiedoston tiedot. Funktioilla findfirst ja findnext käydään läpi löydetyt tiedostot. findfirst:lle annetaan parametreina etsittävät tiedostot, ffblk tietue ja mahdolliset liput.

struct ffblk fblock;
int done;
done = findfirst("c:\\*.*",&fblock,0);
while (!done)
{
cout << "tiedoston nimi: " << fblock.ff_name << " tiedoston koko: " << fblock.ff_fsize << endl;
done = findnext(&fblock);
}

ffblk tietueesta löytyvät mm. seuraavat attribuutit:

Binääritiedoston käsittely

Binäärimuotoisten tiedostojen käsittely vastaa suurilta osin standardia tekstitiedoston käsittelyä. Binääritiedosto saadaan avattua lisäämällä open-kutsuun ios_base::binary-lippu. Kutsut voivat näyttää vaikkapa seuraavilta:

ofstream tdsto("tdsto.dat", ios_base::binary);

ifstream tdsto("tdsto.dat", ios_base::binary);

Jos tietoa halutaan lukea nopeasti tietystä kohtaa tiedostoa se onnistuu binääritiedoston ns. hajakäsittelyn avulla. Hajakäsittelyssä tietoja ei tarvitse käsitellä peräkkäin, vaan tietoja käsitellään tiedosto-osoittimen osoittamasta kohdasta alkaen eteenpäin. Hajakäsittely mahdollistaa olemassaolevien tietojen selailun ja muutoksen. Lisäys sen sijaan tapahtuu aina tiedoston loppuun ellei olemassaolevia tietoja haluta tuhota. Tiedosto-osoittimen siirtäminen tapahtuu seekg ja seekp -metodeilla. Ensimmäistä käytetään tiedoston lukemisen yhteydessä ja jälkimmäistä tiedostoon kirjoittamisen yhteydessä. Siirtyminen tiettyyn kohtaan tiedostoa onnistuu esimerkiksi käskyllä

tdsto.seekg(sijainti);

Tässä sijainti tarkoittaa tiedosto-osoittimen sijaintia tavuina.

Mikä on stringstream?

Stringstream on luokka, jonka avulla merkkijonoja voidaan käsitellä kuin ne olisivat tietovirtoja.

Linkkejä

Kurssimonisteen luku 17: Tiedostot ja makrot

Viimeksi muutettu: ti 25 kesäkuu 2001 3:34:00
Mikko Luukkonen <miklu@st.jyu.fi>
Tekstissä käytetty apuna kurssin luentomonistetta, Päivi Hietasen C++ ja olio-ohjelmointi kirjaa ja useita verkkosivustoja.