Deo zbornika Uvod u programiranje kroz C
C funkcije za čitanje i pisanje
Funkcije getchar
, putchar
, gets
, puts
, printf
i scanf
imaju analogne verzije getc
, putc
, fgets
, fputs
, fprintf
i fscanf
koje rade s datotekama. Sve te funkcije kao prvi argument uzimaju pokazivač na spremnik (FILE
) povezan s datotekom.
Čitanje i pisanje znak po znak
Funkcije:
int getc(FILE *fp)
int fgetc(FILE *fp)
vraćaju sljedeći znak iz datoteke na koju pokazuje fp
. Razlika izmedu getc
i fgetc
je u tome da getc
može biti implementirana kao makro naredba dok fgetc
ne smije. U slučaju greške ili kraja datoteke vraća se EOF
. To je razlog što je tip vraćene vrijednosti int
umjesto char
. Funkcija getchar()
, koju smo ranije upoznali, implementira se kao getc(stdin)
.
Primjer: brojač znakova
Program u sljedećem primjeru broji znakove u datoteci, koja je navedena kao argument komandne linije:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int ch,count=0;
FILE *fpt;
if(argc==1) { /* ime datoteke nedostaje */
printf("\nUporaba: %s ime_datoteke\n",argv[0]);
exit(-1);
}
else if((fpt=fopen(argv[1],"r"))==NULL) {
printf("Ne mogu otvoriti datoteku %s\n",argv[1]);
exit(-1);
}
while((ch=fgetc(fpt))!=EOF) count++;
fclose(fpt);
printf("\nBroj znakova = %d\n",count);
return 0;
}
Znak pročitan sa getc
ili fgetc
može biti vraćen u datoteku pomoću funkcije:
int ungetc(int c, FILE *fp);
Prvi argument je znak koji vraćamo. Znak može biti upisan u datoteku pomoću funkcija:
int putc(int c, FILE *fp)
int fputc(int c, FILE *fp)
Ponovo, razlika izmedu putc
i fputc
je u tome što putc
može biti implementirana kao makro naredba dok fputc
ne smije. Funkcije vraćaju ispisani znak ili EOF
ako je došlo do greške prilikom ispisa. Funkcija putchar(c)
u radu sa fajlovima je definirana kao putc(c, stdout)
.
Primjer: program cat
Funkcija koja kopira jednu datoteku u drugu može biti napisana na sljedeći način:
void cpy(FILE *fpulaz, FILE *fpizlaz) {
int c;
while((c=getc(fpulaz))!=EOF)
putc(c,fpizlaz);
}
Pomoću nje možemo napisati program cat
, koji uzima imena datoteka i ispisuje datoteke na standardnom izlazu, redom kojim su imena navedena. Ukoliko se ne navede ni jedno ime, onda se standardni ulaz kopira na standardni izlaz.
#include <stdio.h>
void cpy(FILE *, FILE *);
int main(int argc, char *argv[]) {
FILE *fpt;
if(argc==1) /* ime datoteke nedostaje */
cpy(stdin,stdout);
else
while(--argc>0)
if((fpt=fopen(*++argv,"r"))==NULL) {
printf("cat: ne mogu otvoriti datoteku %s\n",*argv);
exit(1);
}
else {
cpy(fpt,stdout);
fclose(fpt);
}
return 0;
}
Uočimo da smo u programu posve izbjegli upotrebu brojača time što inkrementiramo i dekrementiramo argc
i argv
.
Čitanje i pisanje liniju po liniju
Funkcija koja učitava podatke iz datoteke liniju po liniju je:
char *fgets(char *buf, int n, FILE *fp);
Prvi argument je pokazivač na dio memorije (eng. buffer) u koji će ulazna linija biti spremljena, a drugi veličina memorije na koju prvi argument pokazuje. Treći argument je pokazivač na datoteku iz koje se učitava. Funkcija će pročitati liniju uključujući i znak za prijelaz u novi red i na kraj će dodati nul znak \0
. Pri tome će biti učitano najviše n-1 znakova, uključivši \n
. Ukoliko je ulazna linija dulja od toga, ostatak će biti pročitan pri sljedećem pozivu funkcije fgets
. Funkcija vraća buf
ako je sve u redu ili NULL
ako se došlo do kraja datoteke ili se pojavila greška.
Funkcija:
char *gets(char *buf);
čita uvjek sa standardnog ulaza. Ona ne uzima veličinu buffera kao argument i stoga se može desiti da je ulazna linija veća od memorije koja je za nju rezervirana. Stoga je bolje umjesto gets(buf)
koristiti fgetf(buf,n,stdin)
. Pri tome treba uzeti u obzir razliku da fgets
učitava i znak \n
, dok gets
znak za prijelaz u novi red učitava, ali na njegovo mjesto stavlja \0
.
Funkcija za ispis podataka u datoteku, liniju-po-liniju je:
int fputs(const char *str, FILE *fp);
Funkcija vraća nenegativnu vrijednost ako je ispis uspio ili EOF
u slučaju greške. fputs
ispisuje znakovni niz na koji pokazuje str
, u datoteku na koju pokazuje fp
. Zadnji nul znak neće biti ispisan i znak za prijelaz u novi red neće biti dodan.
Funkcija:
int puts(const char *str);
ispisuje znakovni niz na koji pokazuje str
na standardni izlaz. Na kraj niza ona dodaje znak za prijelaz u novi red, što ju razlikuje od fputs(str,stdout)
.
Prepoznavanje greške
Budući da ulazne funkcije vraćaju EOF
i u slučaju kada je došlo do greške i u slučaju kada se naiđe na kraj datoteke postoje funkcije:
int ferror(FILE *fp);
int feof(FILE *fp);
koje služe za razlikovanje izmedu pojedinih situacija. ferror
vraća broj različit od nule (istina) ako je došlo do greške, a nulu (laž) ako nije. Funkcija feof
vraća broj različit od nule (istina) ako smo došli do kraja datoteke, a nulu (laž) u suprotnom.
Primjer: detekcija greške
Sljedeći program kopira standardni ulaz na standardni izlaz i detektira ulaznu grešku pomoću funkcije ferror
:
#include <stdio.h>
#define MAXLINE 128
int main(void) {
char buf[MAXLINE];
while(fgets(buf,MAXLINE,stdin) != NULL)
if(fputs(buf,stdout)==EOF) {
fprintf(stderr,"\nIzlazna greska.\n");
exit(1);
}
if(ferror(stdin)) {
fprintf(stderr,"\nUlazna greska.\n");
exit(2);
}
return 0;
}
Izvor: M. Jurak, Programski jezik C, predavanja 2003/04.