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.
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.
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);
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:
- unsigned ff_ftime; /* muuttamisaika */
- unsigned ff_fdate; /* muuttamispäivämäärä */
- long ff_fsize; /* tiedoston koko */
- char ff_fname[13] /* tiedoston nimi */
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.
Stringstream on luokka, jonka avulla merkkijonoja voidaan käsitellä kuin ne olisivat tietovirtoja.
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.