PROGRAMIRANJE II P03 Datoteke doc dr Draen Branin
PROGRAMIRANJE II P-03: Datoteke doc. dr Dražen Brđanin 2014/15
P-03: Datoteke n Sadržaj predavanja n Osnovni pojmovi i klasifikacije datoteka n Datoteke u programskom jeziku C n Rad sa tekstualnim datotekama n Rad sa binarnim datotekama n Standardni tokovi
Datoteke n n DATOTEKA (eng. file) = kolekcija podataka fizički smještena u nekoj sekundarnoj memoriji (hard disk, fleš disk, memorijska kartica, . . . ) Datoteka završava EOF oznakom (terminator datoteke – End of File): n n n EOF terminatori zavise od operativnog sistema: n Windows, DOS: <Ctrl-Z> (ASCII kod: 26) n Unix/Linux: <Ctrl-D> (ASCII kod: 4) Klasifikacija datoteka prema načinu smještanja (reprezentacija) podataka: n tekstualne – datoteka sadrži linije “čitljivog” (korisniku prepoznatljivog) teksta n binarne – datoteka sa binarnim sadržajem u binarnoj (“nečitljivoj” ) reprezentaciji Klasifikacija datoteka prema načinu organizacije (pristupa) podataka: n n n sekvencijalne – zapisi su upisani jedan iza drugog, da bi se pročitao neki zapis moraju da se pročitaju svi prije njega direktne (random) – zapisi počinju na fiksnim adresama (pozicijama) pa se direktno može pristupiti željenom zapisu (bez potrebe da se pročitaju svi prije njega) indeksne (indeksno-sekvencijalne) – zapisi sadrže ključ (za sortiranje podataka) i pokazivač (adresa odgovarajućeg zapisa u sekvencijalnom fajlu gdje se nalaze nesortirani podaci)
Datoteke u programskom jeziku C n n n U programskom jeziku C postoje samo sekvencijalne datoteke = datoteka je tok (uzastopni niz bajtova – eng. stream) Komunikacija sa bilo kojim perifernim uređajem reprezentuje se tokovima Postoji mogućnost direktnog pristupa – svodi se na pozicioniranje na željeni bajt u datoteci n Sve funkcije za rad sa datotekama nalaze se u <stdio. h> n Tip FILE (struktura definisana u stdio. h): n Tip koji reprezentuje datoteku i omogućava manipulaciju datotekom n sadrži sljedeće podatke: n n n deskriptor datoteke (indeks otvorene datoteke u OS tabeli deskriptora) pokazivač trenutne pozicije u datoteci indikator kraja datoteke, indikator greške. . . Da bi se koristila datoteka treba definisati pokazivač na FILE (FILE *fp; )
Tekstualne datoteke n Tekstualna datoteka = datoteka koja sadrži linije teksta (u ASCII kodu) n Linija teksta se završava EOL oznakom (terminator linije – End of Line) n n n Tipični EOL terminatori: n <CR> (“carriage return”, ASCII kod: 13 / 0 x 0 D) n <LF> (“line feed”, ASCII kod: 10 / 0 x 0 A) EOL terminatori zavise od operativnog sistema (jedan ili dva znaka): n Windows, DOS: <CR><LF> n Unix, Linux: <LF> n Mac OS: <CR> Primjeri tekstualnih datoteka: n “plain-text” datoteke formirane editorima teksta, npr. README. TXT n datoteka sa izvornim kodom u nekom programskom jeziku, npr. MAIN. C n HTML, XML, . . .
Binarne datoteke n Binarna datoteka= datoteka koja sadrži zapise u binarnoj reprezentaciji n Binarna reprezentacija: n binarna reprezentacija ASCII kod n nije “čitljivo” u editorima teksta (binarni sadržaj nije razumljiv tekst) n različiti programi mogu različito da interpretiraju istu datoteku n n n samo program (programer) koji je formirao datoteku može uspješno da interpretira binarni sadržaj (jer jedino on zna šta je upisano i kako) Primjeri binarnih datoteka: n izvršni programi (exe, com, dll. . . ), npr. PROGRAM. EXE n audio (wav, m 4 a, raw, . . . ), npr. AUDIO. WAV n video (avi, mpeg, vob, . . . ) npr. VIDEO. AVI n slike (jpg, tif, eps, bmp, . . . ), npr. SLIKA. JPG n . . . Bilo koja datoteka može da se tretira kao binarna (i tekstualna datoteka je binarna, ali binarna nije tekstualna!)
Operacije nad datotekama n Operacije nad datotekom: n n otvaranje n uspostavljanje veze sa fizičkom datotekom n definisanje režima rada (otvaranje nove/postojeće datoteke, dodavanje/preprisivanje zapisa, . . . ) pristup datoteci n čitanje iz datoteke (sa ili bez konverzije) n pisanje u datoteku (sa ili bez konverzije) n pozicioniranje na željeni zapis u datoteci provjera statusa n dobijanje informacije o eventualnim greškama u toku rada, n dobijanje informacije o kraju datoteke, n dobijanje informacije o trenutnoj poziciji pointera za čitanje/upis, . . . zatvaranje n raskidanje veze sa fizičkom datotekom
Otvaranje datoteke n Funkcija za otvaranje datoteke: FILE *fopen(char *imedat, char *rezim); Argumenti: n n char *imedat n string koji reprezentuje naziv datoteke (naziv + ekstenzija, npr. “README. TXT”) n relativna putanja (u odnosu na dati direktorijum, npr. “PODFOLDER\FAJL. TXT” ) n apsolutna putanja (potpuna informacija: npr. “C: \FOLDER\PODFOLDER\FAJL. TXT” ) char *rezim n string koji definiše režim rada (način korišćenja datoteke) n osnovni režimi: “r” / “w” / “a” (read / write / append = čitanje/pisanje/dodavanje) n kombinovani režimi (dodati ‘+’): “r+” / “w+” / “a+” n rad sa binarnim datotekama (dodati ‘b’): “rb” / “r+b” / “w+b” / “a+b” Rezultat izvršavanja: n uspješno otvaranje: pointer na FILE koji omogućava pristup fizičkoj datoteci n neuspješno otvaranje: NULL
Otvaranje datoteke n Režimi rada: Osnovni režimi rada opis “r” Otvaranje datoteke u režimu za čitanje iz postojeće datoteke. Ako datoteka ne postoji, fopen() vraća NULL. “w” Otvaranje datoteke u režimu za upisivanje (prepisivanje preko postojećeg sadržaja). Ako datoteka postoji, piše preko postojećeg sadržaja. Ako datoteka ne postoji, otvara novu. “a” Otvara datoteku u režimu za dodavanje (na kraj datoteke). Ako datoteka ne postoji, otvara novu. Kombinovani režimi rada opis “r+” Otvaranje datoteke i za čitanje i za pisanje. Ako datoteka ne postoji, fopen() vraća NULL. “w+” Otvaranje datoteke i za čitanje i za pisanje. Ako datoteka postoji, piše preko postojećeg sadržaja. Ako datoteka ne postoji, otvara novu. “a+” Otvaranje datoteke i za čitanje i za dodavanje (na kraj datoteke). Ako datoteka ne postoji, otvara novu.
Otvaranje datoteke n n Uobičajene greške kod otvaranja datoteke: n pogrešno ime datoteke (ime koje nije dozvoljeno u OS) n pokušaj da se nepostojeća datoteka otvori u režimu za čitanje n ako se postojeća datoteka otvori u režimu “w”, postojeći sadržaj biće izgubljen Uobičajeni programski obrazac za otvaranje datoteke FILE *fp; if ((fp = fopen(”ime”, rezim))== NULL) //. . . datoteka nije uspjesno otvorena else //. . . datoteka uspjesno otvorena
Zatvaranje datoteke n Funkcija za zatvaranje datoteke: int fclose(FILE *dat); Argumenti: n FILE *dat n pokazivač koji pokazuje na neku otvorenu datoteku Rezultat izvršavanja: n uspješno zatvaranje: 0 n neuspješno zatvaranje: EOF greska = fclose(fp) == EOF n Uobičajeni programski obrazac za zatvaranje datoteke FILE *fp; . . . fclose(fp);
Operacije pisanja/čitanja n Funkcije za pisanje u tekstualnu datoteku: n upis jednog znaka: n n neformatirani upis stringa: n n int fputs(char *string, FILE *dat); formatirani upis: n n int fputc(int znak, FILE *dat); int fprintf(FILE *dat, char *format, . . . ); Funkcije za čitanje iz tekstualne datoteke: n čitanje jednog znaka: n n neformatirano čitanje stringa: n n int fgetc(FILE *dat); char *fgets(char *string, int n, FILE *dat); formatirano čitanje: n int fscanf(FILE *dat, char *format, . . . );
Upis u tekstualnu datoteku n Funkcija za upis jednog znaka u datoteku: int fputc(int znak, FILE *dat); Argumenti: n int znak n n znak koji se upisuje u datoteku FILE *dat n pokazivač na datoteku u koju se upisuje Rezultat izvršavanja: n uspješno upisivanje: ASCII kod upisanog znaka n neuspješno upisivanje: EOF ako je kraj datoteke ili greška greska = fputc(’A’, fp) == EOF;
Upis u tekstualnu datoteku n Funkcija za neformatiran upis stringa u datoteku: int fputs(char *string, FILE *dat); Argumenti: n char *string n n pokazivač na string koji treba da se upiše u datoteku FILE *dat n pokazivač koji pokazuje datoteku u koju se upisuje string Rezultat izvršavanja: n uspješno upisivanje: broj upisanih znakova u datoteku n neuspješno upisivanje: EOF ako je kraj datoteke ili greška greska = fputs(string, fp) == EOF;
Upis u tekstualnu datoteku n Funkcija za formatirani upis u datoteku: int fprintf(FILE *dat, char *format, . . . ); Obavezni argumenti: n FILE *dat n n pokazivač koji pokazuje datoteku u koju se upisuje char *format n konverzioni string (kao kod funkcije printf) Neobavezni argumenti: n lista izraza čije se vrijednosti upisuju datoteke u skladu sa konverzionim stringom Rezultat izvršavanja: n uspješno pisanje: broj upisanih znakova n neuspješno pisanje: negativna vrijednost greska = fprintf(fp, ”%d”, prom) < 0;
Čitanje iz tekstualne datoteke n Funkcija za čitanje jednog znaka iz datoteke: int fgetc(FILE *dat); Argumenti: n FILE *dat n pokazivač na datoteku iz koje se čita Rezultat izvršavanja: n uspješno čitanje: ASCII kod pročitanog znaka n neuspješno čitanje: EOF ako je kraj datoteke ili greška kraj = (znak = fgetc(fp)) == EOF; n Uobičajeni programski obrazac za čitanje znak po znak iz datoteke FILE *fp; unsigned char znak; . . . while ((znak = fgetc(fp)) != EOF) // kod za manipulaciju učitanim znakom
Čitanje iz tekstualne datoteke n Funkcija za neformatirano čitanje stringa iz datoteke: char *fgets(char *string, int n, FILE *dat); Argumenti: n char *string n n int n n n pokazivač na rezultat (adresa od koje počinje rezultat čitanja iz datoteke) maksimalan broj znakova u učitanom stringu (uključujući terminator stringa) FILE *dat n pokazivač koji pokazuje datoteku iz koje se čita Rezultat izvršavanja: n uspješno čitanje: adresa učitanog stringa n neuspješno čitanje: NULL ako je kraj datoteke ili greška greska = fgets(string, 100, fp) == NULL; fgets() čita maksimalno n-1 znakova (ako dodje do EOL završava čitanje)
Čitanje iz tekstualne datoteke n Funkcija za formatirano čitanje iz datoteke: int fscanf(FILE *dat, char *format, . . . ); Obavezni argumenti: n FILE *dat n n pokazivač koji pokazuje datoteku iz koje se čita char *format n konverzioni string (kao kod funkcije scanf) Neobavezni argumenti: n promjenljive (adrese) čije se vrijednosti učitavaju iz datoteke u skladu sa konverzionim stringom Rezultat izvršavanja: n uspješno čitanje: broj konvertovanih (učitanih) podataka n neuspješno čitanje: EOF ako je kraj datoteke ili greška greska = fscanf(fp, ”%d”, &prom) == EOF; Formatirano čitanje ima smisla ako je poznat format po kojem su upisani podaci u datoteku
Pisanje/čitanje u/iz tekstualne datoteke Rezultat izvršavanja: Primjer (upisivanje i čitanje znak po znak): #include <stdio. h> int main() { FILE *fp; int i; if ( (fp = fopen( "tekst. txt" , "w" )) != NULL ) { for (i=0; i<25; i++) putc('a'+i, fp); fclose(fp); Sadrzaj datoteke: abcdefghijklmnopqrstuvwxy // otvaranje za upis // upis znak po znak // zatvaranje datoteke if ( (fp = fopen( "tekst. txt" , "r" )) != NULL ) // otvaranje za citanje { printf("Sadrzaj datoteke: n"); while ( (i = fgetc(fp)) != EOF ) // citanje znak po znak printf("%c", i); fclose(fp); // zatvaranje datoteke } else printf("Greska kod otvaranja datoteke za citanjen"); } else printf("Greska kod otvaranja datoteke za pisanjen"); }
Pisanje/čitanje u/iz tekstualne datoteke Rezultat izvršavanja: Primjer (upisivanje i čitanje stringova): Sadrzaj datoteke: AUTO BLOK KRUG #include <stdio. h> int main() { FILE *fp; char *tekst[] = {"AUTOn", "BLOKn", "KRUGn"}; if ( (fp = fopen( "tekst. txt" , "w" )) != NULL ) { for (int i=0; i<3; i++) fputs(tekst[i], fp); fclose(fp); if ( (fp = fopen( "tekst. txt" , "r" )) != NULL ) { char *s; printf("Sadrzaj datoteke: n"); while ( (s = fgets(s, 10, fp)) != NULL ) printf("%s", s); fclose(fp); } else printf("Greska kod otvaranja datoteke za citanjen"); } else printf("Greska kod otvaranja datoteke za pisanjen"); }
Pisanje/čitanje u/iz tekstualne datoteke Primjer (formatirano upisivanje i čitanje): #include <stdio. h> int main() { FILE *fp; if ( (fp = fopen( "brojevi. dat" , "w" )) != NULL ) { for (int i=1; i<=5; i++) fprintf(fp, "%dn", i); fclose(fp); Rezultat izvršavanja: Sadrzaj datoteke: 1. 00 2. 00 3. 00 4. 00 5. 00 if ( (fp = fopen( "brojevi. dat" , "r" )) != NULL ) { float x; printf("Sadrzaj datoteke: n"); while ( fscanf(fp, "%f", &x) != EOF ) printf("%5. 2 fn", x); fclose(fp); } else printf("Ne moze se otvoriti datoteka u rezimu za citanjen"); } else printf("Ne moze se otvoriti datoteka u rezimu za pisanjen"); }
Rad sa binarnim datotekama n Za upis/čitavanje jednog bajta u/iz datoteke takođe mogu da se koriste funkcije koje se koriste i za tekstualne datoteke: int fputc(int znak, FILE *dat); int fgetc(FILE *dat); n n n Blokovski upis (kopiranje sadržaja memorijskog bloka) u datoteku: int fwrite(void *niz, int size, int count, FILE *dat); Blokovsko čitanje iz datoteke (popunjavanje memorijskog bloka) : int fread(void *niz, int size, int count, FILE *dat); Osnovne karakteristike pisanja/čitanja u/iz binarne datoteke: n n n čitanje/pisanje bloka započinje od trenutne pozicije pokazivača prilikom upisivanja, ako pokazivač nije na kraju prepisuje se preko postojećeg sadržaja (fajl se proširuje ako treba) programer mora da vodi računa o strukturi datoteke
Blokovski upis u binarnu datoteku n Funkcija za blokovski upis u binarnu datoteku: int fwrite(void *niz, int size, int count, FILE *dat); Argumenti: n void *niz n n int size n n veličina pojedinačnog objekta (sizeof(promjenljiva)) koji se upisuje u datoteku int count n n adresa početka memorijskog bloka (adresa promjenljive ili početak niza) odakle se vrši kopiranje u datoteku broj objekata koji se upisuje u datoteku FILE *dat n pokazivač koji pokazuje datoteku u koju se upisuju podaci Rezultat izvršavanja: n uspješno pisanje: broj upisanih objekata jednak count n neuspješno pisanje: broj upisanih objekata manji od count greska = fwrite(niz, sizeof(niz[0]), n, fp) < n;
Blokovsko čitanje iz binarne datoteke n Funkcija za blokovsko čitanje iz binarne datoteke: int fread(void *niz, int size, int count, FILE *dat); Argumenti: n void *niz n n int size n n veličina pojedinačnog objekta (sizeof(promjenljiva)) koji se čita iz datoteke int count n n adresa početka memorijskog bloka (adresa promjenljive ili početak niza) gdje se smještaju pročitani podaci iz datoteke maksimalan broj objekata koji treba da se pročita iz datoteke FILE *dat n pokazivač koji pokazuje datoteku iz koje se čitaju podaci Rezultat izvršavanja: n broj pročitanih objekata
Rad sa binarnim datotekama Primjer (program koji kopira datoteku bajt po bajt): #include <stdio. h> int main(int argc, char *argv[]) { FILE *f 1, *f 2; if (argc < 3) printf("Nema dovoljno argumenatan"); else { if ( (f 1 = fopen(argv[1], "rb")) != NULL ) // ulazna datoteka { if ( (f 2 = fopen(argv[2], "wb")) != NULL ) // izlazna datoteka = kopija { int c; while ( (c = fgetc(f 1)) != EOF ) fputc(c, f 2); fclose(f 2); } else printf("Ne moze se kreirati ciljna datotekan"); fclose(f 1); } else printf("Ne moze se otvoriti ulazna datotekan"); } }
Rad sa binarnim datotekama Primjer (u binarnu datoteku upisuje se niz, a zatim čitanje element po element): #include <stdio. h> typedef struct { float a, b, c; } TROUGAO; int main() { FILE *pf; TROUGAO t, niz[3] = { {2, 3, 4}, {3, 4, 5}, {6, 7, 8} }; if ( (pf = fopen( "trougao. dat" , "wb" )) != NULL ) { if (fwrite(niz, sizeof(TROUGAO), 3, pf) < 1) printf("Greska prilikom upisa!n"); fclose(pf); Rezultat izvršavanja: a= 2. 00 b= 3. 00 c= 4. 00 a= 3. 00 b= 4. 00 c= 5. 00 a= 6. 00 b= 7. 00 c= 8. 00 if ( (pf = fopen( "trougao. dat" , "rb" )) != NULL ) { while ( fread(&t, sizeof(t), 1, pf) ) printf("a=%5. 2 f b=%5. 2 f c=%5. 2 fn", t. a, t. b, t. c); fclose(pf); } else printf("Ne moze se otvoriti datotekan"); }
Pozicioniranje u datoteci n Direktno pozicioniranje u datoteci na željenu poziciju čiji se pomjeraj u bajtovima u odnosu na reper postiže funkcijom: int fseek(FILE *dat, long pomjeraj, int reper); Argumenti: n FILE *dat n n long pomjeraj n n Pomjeraj u bajtovima u odnosu na reper int reper n n pokazivač na otvorenu datoteku mogući reperi: n SEEK_SET ili 0 (početak datoteke), n SEEK_CUR ili 1 (trenutna pozicija), n SEEK_END ili 2 (kraj datoteke) Vraćanje pokazivača pozicije na početak datoteke: void rewind(FILE *dat);
Informacija o poziciji pokazivača n Trenutna pozicija (pomjeraj u odnosu na početak): long ftell(FILE *dat); fp = fopen (“datoteka”, “w”); Indikator = 0 ftell(fp) -> 0 fputc(‘A’, fp); A Indikator = 1 ftell(fp) -> 1 fputs (“string”, fp); A s t r i n g Indikator = 7 ftell(fp) -> 7 rewind(fp); A s t r i n g Indikator = 0 ftell(fp) -> 0
Informacija o poziciji pokazivača Primjer (pozicioniranje i čitanje pozicije): #include<stdio. h> int main() { char *f="datoteka. txt"; FILE *dat; if (dat=fopen(f, "w")) { printf("Na pocetku: %dn", ftell(dat)); fputc('A', dat); printf("Nakon A: %dn", ftell(dat)); fputs("STRING", dat); printf("Nakon STRING: %dn", ftell(dat)); rewind(dat); printf("Nakon premotavanja: %dn", ftell(dat)); fseek(dat, 0, SEEK_END); printf("Kraj : %d", ftell(dat)); fclose(dat); } else printf("Greska!"); } Rezultat izvršavanja: Na pocetku: 0 Nakon A: 1 Nakon STRING: 7 Nakon premotavanja: 0 Kraj : 7
Signalizacija grešaka n n n Svakoj otvorenoj datoteci pridružena su dva logička indikatora: n indikator kraja datoteke n indikator greške Većina funkcija za manipulaciju datotekom kao bočni efekat postavlja ove indikatore Funkcija za brisanje indikatora greške i kraja datoteke void clearerr(FILE *dat); Funkcija za ispitivanje da li je kraj datoteke (nenulta vrijednost ako je kraj) int feof(FILE *dat); Funkcija za ispitivanje indikatora greške (nenulta vrijednost ako je greška) int ferror(FILE *dat); Kodovi i opis grešaka dati su u <errno. h>
Standardni tokovi n n Prilikom pokretanja programa tri predefinisane datoteke (standardni U/I tokovi) se automatski otvaraju: n stdin = standardni ulaz (podrazumijevano tastatura) n stdout = standardni izlaz (podrazumijevano displej) n stderr = standardni izlaz za greške (podrazumijevano displej) Standardni tokovi se automatski otvaraju i mogu da se koriste kao i bilo koja druga datoteka, npr: #include<stdio. h> int main() { char s[100]; fputs("Unesite tekst: ", stdout); fgets(s, 100, stdin); fputs(s, stdout); return 0; } Primjer izvršavanja: Unesite tekst: Programski jezik C
Standardni tokovi n U nekim okruženjima moguće je iz komandne linije (prilikom poziva programa) izvršiti redirekciju (preusmjeravanje) standardnog ulaza i standardnog izlaza : n Preusmjeravanje standardnog ulaza sa tastature na ulaznu datoteku C: >program <ulaz. txt n Preusmjeravanje standardnog izlaza sa displeja na izlaznu datoteku C: >program >izlaz. txt n Istovremeno preusmjeravanje standardnog ulaza i izlaza C: >program <ulaz. txt >izlaz. txt #include<stdio. h> int main() { char s[100]; printf("Unesite tekst: "); fgets(s, 100, stdin); fputs(s, stdout); return 0; } ulaz. txt: 123 Poziv programa iz komandne linije: C: >program <ulaz. txt >izlaz. txt: Unesite tekst: 123
- Slides: 32