Materijali/Čas 14

Čas 14 · FILE*, fopen, fclose, fscanf i fprintf

Fajlovi: otvaranje, čitanje i upis

Podatke prvi put čuvamo van programa. Biramo režim r, w ili a, proveravamo svako otvaranje i čitanje, a zatim bezbedno zatvaramo svaki uspešno otvoren tok.

MAPA ČASA

Od ideje do prvog C programa

1
program
2
podaci
3
promenljiva
4
pseudokod
5
C program

Na kraju je dovoljno da:

  • Objasni šta predstavlja FILE * i zašto se rezultat fopen proverava prema NULL.
  • Izaberi režim r, w ili a prema tome da li čitaš, zamenjuješ ili dopisuješ sadržaj.
  • Proveri da li je fscanf izvršio tačan broj očekivanih dodela.
  • Napiši mali program koji čita iz jednog fajla i upisuje rezultat u drugi.

01 · KORAK

FILE * predstavlja otvoreni tok

Fajl na disku i promenljiva u programu nisu ista stvar. fopen pokušava da poveže program sa fajlom i vraća FILE * koji se koristi u narednim operacijama.

Ako otvaranje ne uspe, rezultat je NULL. Tada nema važećeg toka za čitanje ili upis. Svaki uspešno otvoren tok zatvara se funkcijom fclose kada više nije potreban.

FILE *f = fopen("podaci.txt", "r");
if (f == NULL) return 1;

/* rad sa fajlom */

fclose(f);
Četiri korakaU kratkom programu pronađi otvaranje, proveru, korišćenje i zatvaranje. Zatim objasni šta nedostaje ako se fscanf pozove odmah posle fopen.
NULL nije prazan fajlNULL znači da fajl nije uspešno otvoren. Prazan, ali uspešno otvoren fajl daje važeći FILE *; tek pokušaj čitanja pokazuje da u njemu nema podatka.

02 · KORAK

Režim određuje šta će se desiti sa sadržajem

Režim r služi za čitanje postojećeg fajla. Režim w pravi fajl ili skraćuje postojeći na nultu dužinu, pa se stari sadržaj gubi. Režim a čuva postojeći sadržaj i svaki novi upis stavlja na kraj.

Režim se bira prema nameri programa, ne prema imenu fajla. Ako treba zameniti stari izveštaj, koristi se w; ako se vodi dnevnik, obično a.

fopen("ulaz.txt", "r");     /* čitanje */
fopen("rezultat.txt", "w"); /* novi sadržaj */
fopen("dnevnik.txt", "a");  /* dopisivanje */
Izaberi bez nagađanjaOdredi režim za čitanje bodova, pravljenje novog rezultata i dodavanje jednog reda u dnevnik. Za w i a opiši šta ostaje od starog sadržaja.
Najopasniji je pogrešan wUspešan fopen sa režimom w uklanja prethodni sadržaj pre prvog fprintf. Zato se režim bira pre pokretanja programa nad važnim fajlom.

03 · KORAK

fprintf formatirano upisuje u izabrani tok

fprintf liči na printf, ali kao prvi argument prima FILE *. Ostali argumenti su format i vrednosti koje treba pretvoriti u tekst.

Negativna povratna vrednost označava grešku upisa. Za kratak školski program obavezna je makar provera fopen; pouzdan program proverava i upis i završno zatvaranje.

int broj = 42;
FILE *f = fopen("broj.txt", "w");
if (f == NULL) return 1;
if (fprintf(f, "%d\n", broj) < 0) {
    fclose(f);
    return 1;
}
fclose(f);
Predvidi sadržajAko broj.txt ranije sadrži 100 200, napiši njegov sadržaj posle ovog koda. Zatim zameni w sa a i ponovo odredi sadržaj.
Prvi argument bira odredišteprintf piše na standardni izlaz. fprintf(f, ...) piše u tok f. Formatni string i vrednosti rade na isti način kao kod printf.

04 · KORAK

fscanf se proverava prema broju očekivanih podataka

fscanf prima otvoreni FILE *, format i adrese promenljivih. Vraća broj ulaznih stavki koje su uspešno pretvorene i dodeljene.

Ako očekujemo dva cela broja, uspeh je rezultat 2. Rezultat 1 znači da samo prva promenljiva ima nov podatak; 0 znači da prva konverzija nije uspela, a EOF se može javiti kada kraj ili greška nastupe pre prve dodele.

int a, b;
if (fscanf(f, "%d%d", &a, &b) != 2) {
    fclose(f);
    return 1;
}
printf("%d\n", b);
Ne koristi pola rezultataOdredi povratnu vrednost za sadržaje 17 29, 17 kraj, kraj 29 i prazan fajl. Napiši koje promenljive smeju da se koriste u svakom slučaju.
Poredi sa očekivanim brojemProvera != EOF nije dovoljna kada očekujemo više podataka. Rezultat 1 nije EOF, ali drugi broj ipak nije učitan.

05 · KORAK

Program može istovremeno da koristi ulazni i izlazni fajl

Jedan FILE * može biti otvoren za čitanje, a drugi za upis. Svaki fopen ima svoju proveru. Ako drugi fopen ne uspe, prvi tok se zatvara pre izlaska.

Posle uspešnog čitanja program računa poznatim izrazima i rezultat upisuje pomoću fprintf. Imena pokazivača ulaz i izlaz pomažu da se ne zamene tokovi.

FILE *ulaz = fopen("brojevi.txt", "r");
if (ulaz == NULL) return 1;
FILE *izlaz = fopen("zbir.txt", "w");
if (izlaz == NULL) {
    fclose(ulaz);
    return 1;
}
Prati putanju greškeDovrši program koji učitava tačno tri cela broja i upisuje zbir. Za svaku moguću grešku navedi koji je tok do tog trenutka otvoren i šta mora da se zatvori.
Zatvara se ono što je stvarno otvorenoAko prvi fopen ne uspe, nema toka za zatvaranje. Ako prvi uspe, a drugi ne, zatvara se samo prvi. Ako oba uspeju, zatvaraju se oba.

06 · KORAK

Greške menjaju putanju, ali ne ukidaju čišćenje

Kod sa fajlovima ima više ranih izlaza nego običan račun. Pre svakog return proveravamo koje je tokove program već otvorio.

U ovom času čitamo unapred poznat broj podataka. Čitanje proizvoljnog broja redova i pravilan odnos između povratne vrednosti čitanja i feof obrađujemo u sledećem času.

if (fscanf(ulaz, "%d%d%d", &a, &b, &c) != 3) {
    fclose(izlaz);
    fclose(ulaz);
    return 1;
}
fprintf(izlaz, "%d\n", a + b + c);
fclose(izlaz);
fclose(ulaz);
Proveri sve izlazeU celom programu označi svaki return i uz njega napiši koji tokovi su tada otvoreni. Ispravi svaku putanju na kojoj bi tok ostao nezatvoren.
Petlja kroz fajl dolazi sledećaZa sada fscanf traži tačno određen broj vrednosti. Sledeći čas uvodi petlju koja se završava rezultatom čitanja, kopiranje fajla, tekstualni i binarni režim i fseek.

ZATVARANJE

Brza provera pre domaćeg

  1. Koja je razlika između algoritma i programa?
  2. Šta je ime, a šta vrednost promenljive?
  3. Kako svojim rečima čitaš x = x + 1?
  4. Koji red prvog programa računa, a koji prikazuje rezultat?