58127-1 C-ohjelmointi : 10 Tiedostot
- 10.1 Tiedostoon kirjoittaminen
- 10.2 Formatoitu kirjoittaminen
- 10.3 Binääritiedon kirjoittaminen
- 10.4 Tiedostosta lukeminen
- 10.5 Formatoitu lukeminen tiedostosta
- 10.6 Binääritiedon lukeminen
- 10.7 Tiedostot ja virheet
10 Tiedostot
Tiedostojen käyttö on aika helppoa C-kielessä. Ennen tiedoston käyttöä tiedosto täytyy avata. Tämä tapahtuu funktiolla FILE *fopen(char *TiedostoNimi, char *Tapa, missä TiedostoNimi on tiedoston nimi merkkijonossa ja Tapa kertoo tiedoston käsittelytavan. Tapa kentässä voi olla seuraavia merkkejä:
- "r": tiedostoa luetaan
- "w": tiedostoon kirjoitetaan
- "a": tiedostoon loppuun kirjoitetaan lisää dataa (append)
- "b": tiedostoa käsitellään binääritietoa ei tekstitietona (ei voi käyttää yksinään vaan vaatii yhden ylläolevista)
- "rb" : lue binääritiedostoa
- "wb" : kirjoita binääritietoa
- "ab" : lisää tiedoston loppuun binääritietoa
FILE *file; file = fopen ( "tiedosto.txt", "r" ); FILE *Kuva = fopen ( "kuva.jpg", "wb" );Avattu tiedosto täytyy aina muistaa sulkea funktiolla fclose(). Esimerkiksi:
fclose ( Kuva );
10.1 Tiedostoon kirjoittaminen
Tiedostoon kirjoittamiseen löytyy muutama erilainen funktio. Merkeittäin voi kirjoittaa funktiolla fputc(int Merkki,FILE *Tiedosto). Funktio palauttaa kirjoitetun merkin jos kirjoitus onnistui tai EOF jos sattui virhe.Kokonaisen merkkijonon voi kirjoittaa tiedostoon funktiolla fputs(char *MerkkiJono,FILE *Tiedosto). Palauttaa positiivisen kokonaisluvun jos kirjoitus onnistui tai EOF jos sattui virhe. Esimerkiksi:
#include <stdio.h> int main(void) { int Luettu; FILE *Tiedosto; /* Avataan tiedosto kirjoittamista varten */ if ( (Tiedosto = fopen ( "tiedosto.txt", "w" )) == NULL ) { /* Avaaminen epäonnistui */ printf ( "Tiedostoa \"tiedosto.txt\" ei voitu avata kirjoittamista varten.\n" ); exit ( 1 ); } /* Kirjoita ensin viesti */ fputs ( "Alla on näppäimistöltä syötetty teksti:\n", Tiedosto ); /* lue merkki kerralla kunnes tulee virhe tai EOF */ while ( ( Luettu = getchar () ) != EOF ) { /* tulosta luettu merkki */ fputc ( Luettu, Tiedosto ); } /* suljetaan tiedosto */ fclose ( Tiedosto ); return 0; }
Eri funktioita voi käyttää samaan tiedostoon kirjoittamiseen. Funktiot löytyvät otsikkotiedostosta <stdio.h>.
10.2 Formatoitu kirjoittaminen
Formatoidun kirjoittamisen funktiota fprintf() voidaan käyttää jos haluaa formatoida kirjoitetun tekstin. Toimii kuten normaali printf(), jolla on lisäksi FILE * ensimmäisenä parametrina (eli tiedosto-osoitin, joka saadaan tiedostoa avattaessa). Esimerkki:/* Haetaan dataa jostain */ int Ika = 22; char *Nimi = "Markku Kataja"; char *Juuri = "henkilo"; /* avataan tiedosto */ FILE *Data = fopen ( "uusi.xml", "w" ); fprintf ( Data, "<?xml version=\"1.0\"?>" ); fprintf ( Data, "<%s>\n", Juuri ); fprintf ( Data, "<nimi>%s</nimi><ika>%d</ika>\n", Nimi, Ika ); fprintf ( Data, "</%s>\n", Juuri ); /* valmista, suljetaan tiedosto */ fclose ( Data ); /* ohjelman ajo antaa tuloksena tiedoston uusi.xml joka sisältää: <?xml version="1.0"?> <henkilo> <nimi>Markku Kataja</nimi><ika>22</ika> </henkilo> */
10.3 Binääritiedon kirjoittaminen
Binääritietoa kirjoitetaan funktiolla fwrite(void *Data, size_t Koko, size_t Maara, FILE *Tiedosto).
- Data voi olla osoitin mihin tahansa tyyppin.
- Koko on yhden elementin koko.
- Maara on elementtien määrä, esim. kirjoittaessa taulukkoa.
- Tiedosto on moodissa "wb" avattu tiedosto
#include <stdio.h> int main(void) { int Taulukko[10] = { 1,2,3,4,5,6,7,8,9,10 }; FILE *OutFile; / Avaa tiedosto binääridatan kirjoitusta varten */ if ( (OutFile = fopen ( "binaari.bin", "wb" )) == NULL ) { /* Avaaminen epäonnistui */ printf ( "Tiedostoa \"binaari.bin\" ei voitu avata" ); printf ( "kirjoittamista varten.\n"); exit ( 1 ); } /* Kirjoita koko taulukko tiedostoon *( if ( fwrite ( Taulukko, sizeof (int), 10, OutFile ) != 10 ) { /* Kirjoitus epäonnistui */ printf ( "Virhe kirjoitettaessa tiedostoon!"); } /* sulje tiedosto */ fclose ( OutFile ); return 0; }
Myös tietueita sisältävän taulukon voi kirjoittaa. Esimerkiksi:
struct Aika { unsigned short Tunti; unsigned short Minuutti; unsigned short Sekunti; unsigned short Millisekunti; } /* pieni kalenteri */ struct Aika Kalenteri[200]; int main(void) { /* kaikenlaista tapahtumaa ... */ /* Kijoitetaan kalenteri avoimeen tiedostoon */ if ( fwrite ( Kalenteri, sizeof(struct Aika), 200, Tiedosto ) != 200 ) { /* sattui virhe .... */ } /* Tehdään kaikkea muuta...*/ }
10.4 Tiedostosta lukeminen
Tiedostosta voi lukea merkki kerrallaan funktiolla fgetc(FILE *Tiedosto). Funktio palauttaa kirjoitetun merkin konvertoituna tyypiksi int tai vakion EOF jos syntyi virhe.Kokonaisen merkkijonorivin voi lukea funktiolla fgets(char *Merkkijono, int Koko, FILE *Tiedosto). Funktio lukee maksimissaan Koko -1 merkkiä ja tallettaa ne muuttujaan Merkkijono. Funktio lopettaa lukemisen jos luetaan rivinvaihtomerkki ennen kuin Koko merkkiä on luettu. Viimeisen luetun merkin perään funktio asettaa merkin '\0'. Palauttaa muuttujan Merkkijono jos luku onnistui tai NULL-osoitteen jos syntyi virhe. Esimerkki:
#include <stdio.h> int main (int argc, char **argv) { int Luettu; FILE *Input; FILE *Output; /* Varmista ohjelman parametrien lukumäärä */ if ( argc != 3 ) { printf ( "Väärät parametrit!\nKäyttö: %s alkuperäinen", argv[0] ); printf ( " kopio\n" ); exit ( 1 ); } /* Avaa alkuperäinen tiedosto lukua varten */ if ( (Input = fopen ( argv[1], "r" )) == NULL ) { /* Avaaminen epäonnistui */ printf ( "Tiedostoa %s ei voitu avata.", argv[1]); exit ( 1 ); } /* Avataan tiedosto kirjoittamista varten */ if ( (Output = fopen ( argv[2], "w" )) == NULL ) { /* Avaaminen epäonnistui */ printf ( "Tiedostoa %s ei voitu avata.", argv[2]); exit ( 1 ); } /* Lue merkki kerralla kunnes tulee virhe tai EOF */ while ( ( Luettu = fgetc ( Input ) ) != EOF ) { /* kirjoita merkki kopioon */ fputc ( Luettu, Output ); } /* suljetaan tiedostot */ fclose ( Input ); fclose ( Output ); return 0; }
10.5 Formatoitu lukeminen tiedostosta
Funktiolla fscanf() voidaan lukea formatoitua tietoa tiedostosta samaan tapaan kuin scanf() funktiolla, mutta lisäksi ensimmäisenä parametrina on osoitin tiedostoon (FILE *). Funktio palauttaa luettujen parametrien lukumäärän. Esimerkki:
#include<stdio.h> int main(void) { int Luku; char Merkki; char MerkkiJono[80]; float Reaaliluku; FILE *file; if (!( file = fopen("r","tiedosto.txt") )) { printf("Tiedostoa tiedosto.txt ei voi avata.\n"); exit(1); } if ( ( fscanf(file,"%d%c%s&f",&Luku,&Merkki,MerkkiJono, &Realiluku)) != 4 ) { printf("Luku epäonnistui\n"); exit(1); } /* Tehdään jotain järkevää...*/ fclose(file); return 0; }
10.6 Binääritiedon lukeminen
Binääritiedostoa voidaan lukea funktiolla fread(void *Data, size_t Koko, size_t Maara, FILE *Tiedosto).
- Data on osoitin haluttuun paikkaan ja tyyppiin.
- Koko on yhden elementin koko
- Maara on elementtien määrä, esim. luettaessa taulukkoa
- Tiedosto on moodissa "rb" avattu tiedosto
Funktio on siis funktion fwrite() vastakohta. Palauttaa luettujen elementtien lukumäärän, eli parametrin Maara. Jos tapahtuu virhe palautusarvo on pienempi kuin Maara. Esimerkki:
#include <stdio.h> int main(void) { int Taulukko[100]; int Index, Luettu; FILE *Input; /* Avaa tiedosto binääridatan lukua varten */ if ( (Input = fopen( "testitiedosto.bin", "rb" )) == NULL ) { /* avaaminen epäonnistui */ printf ( "Tiedostoa testitiedosto.bin ei voitu avata."); exit ( 1 ); } /* Lue koko taulukko tiedostosta */ if ( (Luettu = fread( Taulukko, sizeof (int), 10, Input )) != 100 ) { /* Lukeminen epäonnistui */ printf ( "Lukuvirhe, saatiin %d elementtiä\n", Luettu ); } else { /* tulosta saatu taulukko */ for ( Index = 0; Index < 10; Index++ ) printf ( "%d: %d\n", Index, Taulukko[Index] ); } /* sulje tiedosto */ fclose ( Input ); return 0; }
10.7 Tiedostot ja virheet
Tiedoston loppumista voi testata funktiolla feof(FILE *Tiedosto). Funktio palauttaa 0 jos tiedosto on loppu, muuten jonkun toisen arvon.Funktiolla ferror(FILE *Tiedosto) voi testata onko tiedosto-operaatiosta rekisteröitynyt virhettä. Funktio palauttaa 0 jos avatulle tiedostolla Tiedosto ei ole rekisteröity virhettä.
Virhelippu voidaan resetoida funktiolla clearerr(FILE *Tiedosto). Esimerkiksi:
/* avaa tiedosto lukua varten */ if ( (Input = fopen ( argv[1], "r" )) == NULL ) { /* avaaminen epäonnistui */ printf ( "Tiedostoa %s ei voitu avata.\n", argv[1] ); exit ( 1 ); } do { /* lue rivi tiedostosta */ fgets ( Puskuri, 1000, Input ); if ( ferror(Input) ) { perror("Tiedoston luvussa sattui virhe: "); exit(1); } } while ( ! feof ( Input ) && fputs ( Puskuri, stdout ) );
Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)