TIEDOSTOJEN KÄSITTELY
TIEDOSTO-OSOITIN
Tiedosto-osoittimen määrittely
Jotta tiedosto-osoitin saadaan liitettyä ohjelmaan on tehtävä seuraava määrittely:
FILE *fptr;
TIEDOSTON AVAAMINEN
Funktion fopen() määrittely:
FILE *fopen(const char tiedostonimi, const char ”moodi”);
Lauseessa tunniste tiedostonimi on merkkijono, joka kuvaa tiedoston nimeä. Tiedoston nimi voi sisältää myös polkumäärityksen. Parametri moodi määrittää, kuinka tiedosto avataan. Se on merkkijono, joten sen ympärille on laitettava aina lainausmerkit.
Tiedostomoodin tunnisteet:
Esim.merkkijono tarkoitus r Avaa tiedosto vain lukemista varten. Tiedoston on oltava olemassa. w Luo tiedosto kirjoittamista varten. Mikäli ky- seinen tiedosto on jo olemassa, sen päälle kir- joitetaan. a Lisää, avaa tiedosto loppuun kirjoittamista var- ten tai luo tiedosto kirjoitamista varten, ellei tiedostoa ole olemassa. r+ Avaa olemassa oleva tiedosto päivittämistä var- ten (lukeminen tai kirjoittaminen). w+ Luo tiedosto päivitystä varten (lukeminen tai kirjoittaminen). Jos kyseinen tiedosto on ole- massa, sen päälle kirjoitetaan. a+ Avaa tiedosto lisäämistä varten, tiedoston lop- puun päivittämistä varten tai luo tiedosto, el- lei sitä ole olemassa.
Funktio fopen() palauttaa osoittimen tiedostoon. Mikäli tiedostoa avattaessa tapahtuu virhe, funktio palauttaa NULL -osoittimen.FILE *fileptr; fileptr = fopen(”CONFIG.SYS”, ”r”);
Haluttaessa varmistua siitä, että tiedoston avaus onnistui, voidaan käyttää seuraavaa koodijaksoa.
FILE *fptr; if (( ftpr = fopen(”C:\\TEST.DAT”, ”r”)) == NULL ) { printf(”Virhe: Tiedoston avaaminen ei onnistunut\n”); exit (0); }
I/O -FUNKTIOIDEN KÄYTTÄMINEN MERKKITIEDOSTOJEN YHTEYDESSÄ
Merkkien lukeminen:
Esimerkkiohjelma matkii DOS:n type-komentoa. Ohjelmalle annetaan tiedoston nimi jonka sisältö sitten tulostetaan näytölle.
Esim.
/*tekstitiedostojen avaamiseen joiden pääte on esim. txt, c tai cpp. Jos koodi1.c -tiedosto sijaitsee esim F-asemassa Teksti-kansiossa, kirjoita "Anna tiedoston nimi" vastaukseksi seuraava: F:/Teksti/koodi1.c ja paina Enter */ #include <stdio.h> #include <stdlib.h> int main() { char ch, filename[85]; FILE *fileptr; printf("Avattava tekstitiedosto voi olla esim txt-päätteinen.\n"); printf("Avaa tietokoneellesi tai verkkoasemaan talletettu tiedosto.\n\n"); printf("Anna tiedoston sijainti ja tiedoston nimi\n"); gets(filename); if ((fileptr = fopen(filename, "r")) == NULL) { printf("\nTiedoston avaus ei onistunut"); sleep(2000); exit (0); } printf("Tiedoston %s tulostus\n\n"A, filename); while (!feof (fileptr)) { ch = fgetc(fileptr); putchar(ch); } fclose(fileptr); getch(); return 0; }
Ohjelmassa luetaan tiedostosta fgetc()-funktiolla merkki kerrallaan ja tulostetaan näytölle merkeittäin funktiolla putchar().
while-silmukassa käytetään funktiota feof() etsimään tiedoston loppumerkkiä (EOF). Tiedoston loppumerkki on erikoismerkki, jonka käyttöjärjestelmä asettaa kunkin tiedoston loppun. Lopumerkin tehtävänä on kertoa käyttöjärjestelmälle tiedoston loppumisesta. Tästä syystä esimerkissä voidaan jatkaa merkkien lukemista niin kauan kunnes saavutetaan tiedoston loppu. Kun funktion feof() arvo tulee todeksi, silmukasta poistutaan ja tiedosto suljetaan. Tiedoston sulkeminen tapahtuu funktion fclose() avulla. Funktio sulkee tiedoston, joka tunnistetaan tiedoston osoitinparametrin avulla. Funktio palauttaa arvon, joka ilmaisee, pystyttiinkö tiedosto sulkemaan. Esimerkkiohjelmassa ei tuota arvoa tarkastettu erikseen.
Merkkien kirjoittaminen:
Kirjoittaminen tiedostoon merkki kerrallaan tapahtuu funktion fputc() avulla. Funktion fputc() yleinen muoto:
Arvo on kokonaislukuvakio, joka määrittää, mikä merkki kirjoitetaan tiedostoon. Tunniste fileptr osoittaa FILE-muuttujaan, joka avaa tiedoston.int fputc(int c, FILE *fileptr);
Esim.FILE *fptr; fptr = fopen(”FILE.TXT”, ”w”); fputc(”p”, fptr); fclose(fptr);
/* Ohjelma kirjoittaa merkkejä tiedostoon */ #include <stdio.h> #include <stdlib.h> #include <process.h> int main() { char ch, filename[85]; FILE *fileptr; printf(”Anna tiedoston nimi\n”); gets(filename); printf(”Lopetus merkillä # tyhjälle riville\n”); if ((fileptr = fopen(filename, ”w”)) == NULL) { printf(”Tiedoston avaaminen ei onnistunut\n”); exit (0); } while (( ch = getchar()) != ‘#’) fputc(ch, fileptr); fclose(fileptr); return 0; }
Ohjelma sijottaa silmukassa jokaisen kirjoitetun merkin tiedostoon kunnes syötetään merkki #. Tämän jälkeen tiedosto suljetaan ja ohjelma päättyy. Jokainen merkinpainallus ei aiheuta kirjoittamista levylle vaan merkit kirjoitetaan ensin puskuriin. Puskuri kirjoitetaan levylle sen tultua täyteen tai kun tiedosto suljetaan funktiolla fclose().
I/O -FUNKTIOIDEN KÄYTTÖ MERKKIJONOJEN KANSSA
Esim.
#include <stdio.h> #include <stdio.h> #include <process.h> #define MAXLINELEN 135 int main() { char filename[85], strline[MAXLINELEN]; int line = 0; FILE *fileptr; printf(”Anna tiedostonimi\n”); gets(filename); if ((fileptr = fopen(filename, ”r”)) == NULL) { printf(”Tiedosto ei aukea\n”); exit (0); } while (!feof(fileptr)) { fgets(strline, MAXLINELEN, fileptr); printf(”%s”, strline); line++; } fclose(fileptr); printf(”\n%d riviä oli tiedostossa\n”, line); return 0; }
Ohjelmassa käytetään funktiota fgets(). Funktio käyttää kolmea parametria: merkkitaulukko, johon merkkijono tallennetaan. Seuraava parametri on merkkijonoon luettavien merkkien maksimipituus. Tämä parametri estää funktiota lukemasta liian pitkää merkkijonoa ja samalla ylittämästä taulukon rajoja. Kolmas parametri on tiedosto-osoitin, joka kertoo funktiolle mitä tiedostoa käsitellään.
Esim.fgets(strline, MAXLINELEN, fileptr);
/* Ohjelma kirjoittaa merkkijonoja levytiedostoon */ #include <stdio.h> #include <stdio.h> #include <string.h> #define MAXLINELEN 135 int main() { char filename[85], strline[MAXLINELEN]; FILE *fileptr; printf(”Lopetus: Enter tyhjällä rivillä\n”); printf(”Anna tiedostonimi\n”); gets(filename); if ((fileptr = fopen(filename, ”w”)) == NULL) { printf(”Tiedosto ei aukea\n”); exit (0); } while (strlen(gets(strline)) > 0) { fputs(strline, fileptr); fputs(”\n”, fileptr); } fclose(fileptr); return 0; }
Ohjelman while-silmukka tarkastaa merkkijonon pituuden. Mikäli merkkijonon pituus on nolla silmukka päättyy. Muutoin funktio fputs() tulostaa merkkijonon avoimeen tiedostoon. Funktio fputs() ei suorita rivinvaihtoa vaan tämä on tehtävä omalla lauseella.
ERIMUOTOISTEN TIETOJEN SYÖTTÖ / TULOSTUS
Funktiot fprintf() ja fscanf()
Esim.int fprintf(FILE *stream, const char *format [, argumentti, ...]); int fscanf(FILE *stream, const char *format [, osoite, ...]);
Esim. Ohjelmaesimerkki fprintf().fprintf(fptr, ”Muuttujan arvo on %d”, a + b); fscanf(fptr, ”%d”,x);
Ohjelmassa fprintf()-funktio saa yhden parametrin enemmän kuin tavallinen printf()-funktio. Lisäparametri on tiedosto-osoitin, joka viittaa tiedostoon johon kirjoitetaan. Muotoilumääreet ovat samat kuin printf()-funktiossa.#include <stdio.h> #include <process.h> #include <conio.h> #include <string.h> #include <ctype.h> int main() { char cont[2]; char name[25]; int age; FILE *fileptr; if ((fileptr = fopen(”NAMES.DAT”,”w”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } strcpy(cont, ”Y”); while (strcmp(”Y”, cont) == 0) { printf(”Anna nimi:\n); scanf(”%s”, name); printf(”Anna ikä\n”); scanf(”%d”,&age); fprintf(fileptr, ”%s %d\n”, name, age); printf(”Annatko toisen nimen (K / E)\n”); scanf(”%s”,cont); cont[0] = toupper(cont[0]); } fclose(fileptr); return 0; }
Esim. Ohjelmaesimerkki fsanf().
#include <stdio.h> #include <process.h> #include <stdlib.h> int main() { char buffer[25]; int number; FILE *fileptr; if ((fileptr = fopen(”NAMES.DAT”,”r”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } while (!feof(fileptr)) { fsanf(fileptr, ”%s”, buffer); printf(”Nimi = %s, ”, buffer); fsanf(fileptr, ”%d”, &number); printf(”Ikä on %d\n”, number); } fclose(fileptr); return 0; }
TIEDOSTOKOHTAISET SUORASAANTITOIMINNOT I/O
Esim. Näyttää tiedoston käänteisenä.
#include <stdio.h> #include <process.h> int main() { char ch, filename[85]; FILE *fileptr; long lastpos; printf(”Anna tiedoston nimi\”); gets(filename); if ((fileptr = fopen(filename, ”r”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } fseek(fileptr, 0, SEEK_END); lastpos = ftell(fileptr); while(!feof(fileptr)) { fseek(fileptr, --lastpos, SEEK_SET); ch = fgetc(fileptr); putchar(ch); } fclose(fileptr); return 0; }
Ohjelma soveltuu käytettäväksi ASCII-tiedoston kanssa.
Ohjelmassa on kaksi funktiota fseek() ja ftell(). fseek() mahdollistaa suurtymisen mihin kohtaan tahansa tiedostossa. Funktio ftell() palauttaa long tyyppisen tiedon, joka kertoo nykyisen sijaintikohdan tiedostossa. Todellisuudessa funktio palauttaa tavujen määrän tiedoston alusta alkaen ja ensimmäinen tavu on numeroitu tavuksi nolla. Ohjelmassa käytetään funktiota fseek() siirtymisessä tiedoston loppuun (SEEK_END), jonka jälkeen funktio ftell() palauttaa sen hetkisen sijaintikohdan tiedostossa. Sijaintikohta talletetaan muuttujan lastpos.
Funktion fseek() yleinen muoto
Funktio käyttää kolmea parametria, joista ensimmäinen osoittaa käsiteltävään tiedostoon. Seuraava argumentti, offset, on long-tyyppinen ja se ilmaisee, kuinka pitkälle lähtökohdasta on siirryttävä. Siirtymä voi olla positiivinen, jolloin siirrytään eteenpäin tai negatiivinen, jolloin siirrytään taaksepäin. Mikäli parametri offset on nolla mitään siirtymää ei tapahdu. Kolmas argumentti on nimeltään whence, joka esittää alkupisteen josta siirtymä lasketaan. Funktio fseek palauttaa nollan, jos siirtyminen onnistuu ja nollasta poikkeavan arvon, jos tiettyyn kohtaan siirtyminen ei onnistunut.int fseek(FILE *stream, long offset, int whence);
Vakiot parametrille whence:
Vakion nimi Arvo Alkupiste SEEK_SET 0 Tiedoston alku SEEK_CUR 1 Nykyinen sijainti SEEK_END 2 Tiedoston loppu
TIETUEIDEN KIRJOITTAMINEN JA LUKEMINEN
Esim. Ohjelma kirjoittaa tietuemuotoista tietoa levylle.
#include <stdio.h> #include <string.h> #include <process.h> #include <ctype.h> struct inforec { char name[85]; int age; }; int main() { char ch = ‘N’; char filename[85]; FILE *fileptr; struct inforec person; printf(”Anna tiedoston nimi: \n”); gets(filename); if ((fileptr = fopen(filename, ”w”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } do { printf(”Anna nimi\n”); scanf(”%s”;person.name); printf(”Anna ikä\n”); scanf(”%d”, &person.age); fwrite(&person, sizeof(person), 1, fileptr); fflush(stdin); printf(”Lisäätkö nimen tiedostoon (K/E)\n”); ch = getchar(); } while (toupper(ch) == ‘K’); fclose(fileptr); printf(”\nTiedoston %s tallennus OK\n”, filename); return 0; }
Esimerkkiohjelmassa on funktio fwrite(). Funktio käyttää neljää argumenttia, joista ensimmäinen on puskurin sijaintipaikka, johon tieto talletetaan. Toinen argumentti määrittää, kuinka monta tavua kirjoitetaan. Kolmas argumentti määrittää, kuinka monta tietuetta kirjoitetaan. Viimeinen argumentti on FILE-osoitin.
Mikäli funktio palauttaa arvon yksi on kirjoittaminen onnistunut. Nolla paluuarvona merkitsee kirjoittamisen epäonnistumista.
Tietueiden lukeminensize_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream); FILE *fptr; char str[10]; fwrite(&str, sizeof(str), 1, fptr);
Funktion fwrite() vastapuoli on funktio fread(). Funktio lukee tietyn määrän tavuja ja tallentaa tiedot muistipaikkaan.
Ensimmäinen parametri on osoite puskuriin, johon luettu tieto talletetaan. Toinen parametri kertoo, kuinka monta tavua kuhunkin tietueeseen luetaan. Kolmas parametri ilmaisee, kuinka monta tietuetta luetaan. Viimeinen parametri on FILE-osoitin avoimeen tiedostoon.size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
Esim. Ohjelma lukee tietueita levytiedostosta.FILE *fptr; char str[10]; fread(&str, sizeof(str), 1, fptr);
#include <stdio.h> #include <stdlib.h> #include <process.h> struct inforec { char name[85]; int age; }; int main() { char ch, filename[85]; FILE *fileptr; int recnumb = 1; struct inforec person; printf(”Anna Tiedoston nimi\n”); gets(filename); if ((fileptr = fopen(filename,”r”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } while(fread(&person, sizeof(person), 1, fileptr) == 1) { printf(”Tietue # %d\n”, recnumb++); printf(”Nimi on %s\n”, person.name); printf(”Ikä on %d\n”, person.age); printf(”Paina Enteriä siirtyäksesi seuraavaan tietueeseen\n”); ch = getchar(); } fclose(fileptr); printf(”Tiedoston loppu”); return 0; }
TAULUKOIDEN KIRJOITTAMINEN JA LUKEMINEN
Esim. Ohjelma lukee ja kirjoittaa taulukon.
#include <stdio.h> #include <stdlib.h> #include <process.h>> #define ITEMS 7 int main() { char filename[85]; int count; FILE *fileptr; int data[ITEMS] = { 8, 57, 5, 309, 33, 87,55}; int data[ITEMS]; printf(”Anna tiedoston nimi\n”); gets(filename); /* kirjoitetaan taulukko tiedostoon */ if ((fileptr = fopen(filename,”w”)) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } printf(”Kirjoitetaan tietoalkioita tiedostoon %s\n”, filename); fwrite(data, sizeof(data), 1, fileptr); fclose(fileptr); /*luetaan tiedosto taulukkoon */ if ((fileptr = fopen(filename, ”r”) == NULL) { printf(”Tiedostoa ei voi avata”); exit (0); } printf(”Luetaan tietoalkioita tiedostosta \n”); fread(&data2, sizeof(data), 1, fileptr); fclose(fileptr); printf(”Taulukon jäsenet ovat \n”); for (count = 0; count < ITEMS; count++) printf(”Alkio %d on %d\n”, count, data2[count]); return 0; }
Ohjelma tallentaa seitsemän alkion taulukon käyttäjän määrittelemään levytiedostoon. Tämän jälkeen luetaan tiedot takaisin erilliseen taulukkoon ja tulostetaan ne näytölle.