Soubor
Velká část programů potřebuje pracovat se získanými informacemi i při dalším spuštění. K tomu je nutné znát možnosti práce se soubory. Souborem rozumíme posloupnost Bytů, uložených na paměťovém médiu, nejčastěji na pevném disku. Každý soubor má svůj název, určený v souladu s pravidly daného operačního systému. Příponu souboru většinou využíváme k bližšímu určení typu souboru. V názvu souboru v jazyce C je vhodné používat jen písmena anglické abecedy, číslice a podtržítko.
V jazyce C pracujeme s dvěma druhy souborů - jedná se o soubory textové a binární. Textové soubory obsahují řádky textu (můžeme v nich ale pracovat i s číselnými údaji), jejich obsah si můžeme prohlídnout, případně taky změnit v textovém editoru. Binární soubor obsahuje informace zapsány binárně (zakódované).
Pokud chceme v jazyce C pracovat se souborem, musíme ho nejdříve otevřít a po ukončení práce s ním je potřebné ho uzavřít. Když máme soubor otevřený, můžeme z něj číst uložené informace nebo do něj zapisovat nové informace. Při práci se souborem využívá operační systém vyrovnávací paměť (buffer). Když potom v programu použijeme příkaz pro uložení hodnoty do souboru, neukládá se fyzicky přímo do souboru, ale nejdřív do vyrovnávací paměti a až po její naplnění se data přesunou do souboru. Aby se tedy nestalo, že některé údaje nakonec nebudou uloženy v souboru, je nutné používat v programu příkaz pro uzavření souboru hned po ukončení práce s ním.
Základní funkce pro práci se souborem
Pokud chceme v programu pracovat se souborem, musíme do něj vložit hlavičkový soubor stdio.h. Při práci se souborem v jazyce C používáme proměnnou datového typu FILE*.
Deklarace proměnných pro práci se souborem:
FILE *soubor;
FILE *fw, *fr;
Otevření a uzavření souboru
Pro otevření souboru používáme funkci fopen(). Funkce má dva parametry. Prvním parametrem je cesta k fyzickému souboru, který použijeme pro zápis nebo čtení dat, zapisujeme ji jako řetězec (t.j.v uvozovkách nebo jako proměnnou pro řetězec). Pokud uvedeme jen název souboru, ne celou cestu, předpokládá se, že soubor je uložen v aktuálním adresáři. Druhý parametr určuje režim práce s daty, zapisujeme ho taky jako řetězec.
V případě úspěšného otevření souboru vrátí funkce fopen() proměnnou typu FILE*. V případě chyby při otevírání souboru vrátí hodnotu NULL.
Režim otevření souboru:
"r" - otevření existujícího textového souboru pro čtení
"w" - otevření textového souboru pro zápis. V případě, že soubor neexistuje, vytvoří se. V případě, že soubor existuje, data se přepisují (původní data jsou vymazány)
"a" - otevření textového souboru pro přidávání na konec. V existujícím souboru se aktuální pozice nastaví na konec. Pokud soubor neexistuje, vytvoří se.
Další režimy:
"r+" "w+" "a+" - soubor je otevřen pro čtení i zápis, základní nastavení režimu určuje uvedené písmeno. Je vhodné používat samotný režim čtení nebo zápisu a ne jejich kombinaci
"rb" "wb" "ab" "rb+" "wb+" "ab+" - režimy pro binární soubor
Příklad otevření textového souboru pro čtení (s testováním, zda se otevření podařilo):
FILE *f;
f = fopen("data.txt","r");
if(f == NULL){
printf("Chyba pri otevirani souboru!");
return -1;
}
Po skončení práce se souborem, musíme soubor uzavřít. K tomu používáme funkci fclose(). Jejím parametrem je proměnná typu FILE*, která určuje soubor, který chceme uzavřít. V případě úspěšného uzavření souboru funkce vrátí hodnotu 0. V případě, že se soubor nepovedlo uzavřít, vrátí symbolickou konstantu EOF (end of file). Jedná se o konstatntu, která je definována v hlavičkovém souboru stdio.h a používá se pro označení konce souboru.
Příklad uzavření textového souboru (s testováním, zda se uzavření podařilo):
if(fclose(f) == EOF){
printf("Chyba pri zavirani souboru!");
... //dalsi prikazy pro pripad chyby
}
Funkce fopen() a fclose() se používají pro textový i binární soubor.
Textový soubor
Výhodou textových souborů je, že data můžeme jednoduše kontrolovat. Textový soubor je soubor, který můžeme vytvořit, prohlížet a editovat taky v jednoduchém textovém editoru např. v Poznámkovém bloku. Tzn. že si data do souboru můžeme předem připravit a program už s nimi dále pracuje: čte, přepisuje nebo přidává.
V této části se seznámíme s funkcemi pro zápis do souboru a čtení z textového souboru. Funkce jsou velmi podobné jako funkce pro čtení a zápis pro standardní zařízení, t.j. vstup z klávesnice a výstup na monitor.
Pro formátované čtení a zápis slouží funkce fscanf() a fprintf(). Obě mají tři parametry, kde první parametr je proměnná typu FILE*. Další parametry jsou stejné jako parametry u funkcí scanf() a printf(). Návratová hodnota funkce fscanf() je počet přečtených položek.
fprintf(f, "%d ", x);
- příkaz uloží do souboru, určeného proměnnou f, hodnotu proměnné x. V programu musí být soubor, reprezentovaný proměnnou f, otevřený pro zápis. Funkce fprintf() se dá použít pro zápis číselných i textových hodnot do textového souboru.
fscanf(f, "%d", &x);
- příkaz načte ze souboru, určeného proměnnou f, celočíselnou hodnotu do proměnné x. V programu musí být soubor, reprezentovaný proměnnou f, otevřený pro čtení. Funkce fscanf() je vhodná pro čtení číselných hodnot z textového souboru. V případě chyby vrací funkce hodnotu EOF.
Speciální příkazy pro čtení a zápis znaku do souboru jsou fgetc() a fputc(). Parametrem příkazu fgetc() je proměnná typu FILE*, vrací načtenou hodnotu. Funkce fputc() má dva parametry, a to znak a proměnnou typu FILE*.
fputc(c, f);
- příkaz uloží znak c do souboru, určeného proměnnou f. V programu musí být soubor, reprezentovaný proměnnou f, otevřený pro zápis.
c = fgetc(f);
- příkaz načte ze souboru, určeného proměnnou f, znak do proměnné c. V programu musí být soubor, reprezentovaný proměnnou f, otevřený pro čtení. Funkce se využívá pro čtení textu ze souboru po znacích. V případě chyby vrací funkce hodnotu EOF.
Speciální příkazy pro čtení a zápis řetězce do souboru jsou fgets() a fputs(). Funkce fgets() načte řetězec ze souboru, načítání se řídí znakem koncem řádku. Funkce tedy načítá řádky, má tři parametry. Prvním je proměnná, do které se načte řetězec ze souboru. Druhým parametrem je omezení maximální délky načítaného řetězce, které se uvádí v počtu znaků. Posledním parametrem je proměnná typu FILE*, která určuje, z jakého souboru se čte. Funkce fputs() uloží řetězec, uvedený jako první parametr funkce, do souboru, který určuje druhý parametr funkce.
fputs(radek, f);
fgets(radek, 80, f);
- příkaz načte ze souboru, určeného proměnnou f, řetězec o maximální délce 80 znaků a uloží ho do proměnné radek. V programu musí být soubor, reprezentovaný proměnnou f, otevřený pro čtení. Příkaz čte řádky ze souboru včetně znaku '\n'. Funkce je vhodná pro čtení textů (řetězců) z textového souboru. V případě chyby vrací funkce hodnotu NULL.
Program uloží do souboru zadaná reálná čísla, jejich zadávání ukončí uživatel číslem 0.
#include <stdio.h> #include <stdlib.h> #define KON_ZNACKA 0 int main() { FILE *f; int pocet=0; float cislo; //otevreni souboru f=fopen("data.txt","w"); if(f==NULL) { printf("\nSoubor se nepovedlo otevrit\n"); system("pause"); exit (1); } //zadavani hodnot s koncovou znackou printf("Zadejte cisla, konec zadavani:%d\ ", KON_ZNACKA); do{ printf("%d. hodnota: ", pocet+1); scanf("%f", &cislo); if (cislo != KON_ZNACKA) { fprintf(f,"%f ",cislo); } }while (cislo != KON_ZNACKA); if (fclose(f)==EOF) printf("Soubor se nepovedlo zavrit"); system("pause"); return 0; }
Funkce načte reálná čísla z textového souboru a uloží je do pole. Název souboru, včetně přípony, zadá uživatel. Funkce vrátí počet hodnot v poli.
int ze_souboru_do_pole (float cisla[]) { FILE *f; int pocet=0, i=0; float x; char nazev[30]; printf("Zadejte cely nazev souboru: "); scanf("%s", nazev); //lze pouzit scanf(), neocekavame mezery f=fopen(nazev,"r"); //otevreni souboru pro cteni if(f == NULL) { return -1; //v pripade chyby funkce skonci a vrati -1 } while( fscanf(f,"%f",&x) != EOF) //cteni ze souboru az do konce souboru { cisla[i] = x; //je vhodne doplnit kontrolu pro max.rozsah pole i++; pocet++; } if (fclose(f) == EOF) return -2; return pocet; //funkce vrati pocet hodnot ulozenych do pole }
Poznámka: Při ukládání do souboru často víme, kolik hodnot chceme do souboru uložit. Proto nastavení smyčky nebývá problém. Když otevíráme soubor pro čtení, nevíme většinou, kolik údajů je v něm aktuálně uloženo. Pro nastavení smyčky pro čtení ze souboru využíváme proto návratovou hodnotu použité funkce. Všechny funkce pro čtení ze souboru vrací při neúspěšném čtení specifickou hodnotu. Smyčka je potom nastavena "čti hodnotu, pokud není neúspěch". Např. funkce fscanf() a fgetc() vrací v případě neúspěchu hodnotu EOF, funkce fgets() vrací při neúspěchu NULL.