Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 2 - Práce s textovými soubory v jazyce C

V minulé lekci, Úvod do práce se soubory v jazyce C, jsme si udělali úvod do práce se soubory.

V dnešním C tutoriálu se naučíme pracovat s textovými soubory, které jsou nejjednodušší a také je asi budeme využívat nejčastěji. Do textových souborů zapisujeme nebo je čteme po řádkách. Lze je samozřejmě číst/zapisovat i po znacích, ale řádkový přístup je určitě lidštější. K zápisu do souboru budeme používat funkci fprintf() a ke čtení fscanf(). Dvojice funkcí funguje úplně stejně jako printf() a scanf(), které pracovali se standardním vstupem/výstupem (konzolí). Tyto funkce ovšem pracují se souborem. Odkaz na soubor předáme vždy jako první parametr funkce.

Otevření souboru

Předtím, než se souborem začneme pracovat, musíme ho otevřít. K tomu slouží funkce fopen(). Při otevírání souboru specifikujeme mód, pro který soubor otevíráme. Nejčastěji je to "w" (zápis), "r" (čtení) nebo "a" (připisování).

Zavření souboru

Po dokončení práce se souborem ho je třeba zavřít. Asi byste uhodli, že k tomu slouží funkce fclose(). Pokud bychom soubor zapomněli zavřít, chápal by operační systém jako že s ním stále pracujeme. Ostatní programy by ho nemohly používat a také bychom zbytečně plýtvaly zdroji, protože operační systém má na počet najednou otevřených souborů většinou nějaké limity. V neposlední řadě bychom si měli sdělit, že práce se soubory používá tzv. buffer. Zapisovat totiž znak po znaku by disk velmi vytížilo, proto se čeká, až se naplní určitá vyrovnávací paměť, která se potom najednou na disk zapíše a tím se ušetří přístupy k disku. Kdybychom zapomněli zavolat fclose(), mohl by ve vyrovnávací paměti zůstat ještě nějaký text, který by se do souboru nedopsal.

Zápis do souboru

Uveďme si konečně příklad a to vytvoření jednoduchého textového souboru s dopisem. Záhy si ho vysvětlíme:

int main(int argc, char** argv) {
    FILE * p_soubor = fopen("dopis.txt", "w");
    if (p_soubor == NULL)
    {
        printf("Soubor se nepodařilo otevřít pro zápis, zkontrolujte prosím oprávnění.");
        return 1;
    }

    fprintf(p_soubor, "Drahá Brynn,\n");
    fprintf(p_soubor, "opatruj se, Malcolm unikl a jistě si pro mne brzy přijde jako pro prvního.\n");
    fprintf(p_soubor, "Musíš navést Brandona, dovést ho k amuletu, klíčem k zaříkávadlu by možná\n");
    fprintf(p_soubor, "mohla být levandulová růže.\n\n");
    fprintf(p_soubor, "Kallak\n");

    if (fclose(p_soubor) == EOF)
    {
        printf("Soubor se nepodařilo uzavřít.");
        return 1;
    }

    return (EXIT_SUCCESS);
}

Na začátku zavoláme funkci fopen(), které sdělíme, že chceme otevřít soubor dopis.txt v módu pro zápis. Pokud soubor neexistuje, bude vytvořen. Pokud již existuje, bude přepsán! Funkce vrací ukazatel na strukturu typu FILE. Právě přes tento ukazatel budeme se souborem dále pracovat a proto si ho uložíme.

Soubor se nemusí podařit otevřít a to hlavně tehdy, když k němu nemá program přístup. Stane se tak, když program např. spustíme z disku CD, kam nelze zapisovat, nebo když ho spustíme např. přímo na disku C (mimo uživatelské složky jako jsou dokumenty nebo plocha, kam máme povoleno zapisovat). Při této situaci vrátí NULL (tedy prázdný ukazatel) a na tuto hodnotu bychom měli reagovat.

Prostřední část programu je triviální, pouze zapisujeme do souboru řádky textu pomocí fprintf(). Samozřejmě bychom mohli zapisovat např. i proměnné a to takto:

int hlasitost = 100;
fprintf(p_soubor, "hlasitost=%d", hlasitost);

Stejně, jako se nemusí povést otevření souboru, nemusí se podařit ani jeho uzavření. Funkce fclose() v tomto případě vrátí hodnotu EOF (jako End Of File).

Když aplikaci spustíme, vytvoří se v aktuální složce s programem soubor dopis.txt s následujícím obsahem:

Vytvoření textového souboru v jazyce C - Práce se soubory v jazyce C

Čtení ze souboru

Čtení ze souboru je velmi obdobné. Napíšeme si opačnou aplikaci, která dopis načte a vypíše na obrazovku. Budeme předpokládat, že nevíme, kolik má řádků a proto si ukážeme jak načíst všechny řádky ze souboru.

int main(int argc, char** argv) {
    FILE * p_soubor = fopen("dopis.txt", "r");
    if (p_soubor == NULL)
    {
        printf("Soubor se nepodařilo otevřít pro čtení, zkontrolujte prosím zda existuje.");
        return 1;
    }

    char buffer[1024];
    while (fscanf(p_soubor, " %1023[^\n]", buffer) != EOF)
    {
        printf("%s\n", buffer);
    }

    if (fclose(p_soubor) == EOF)
    {
        printf("Soubor se nepodařilo uzavřít.");
        return 1;
    }

    return (EXIT_SUCCESS);
}

Otevření souboru je stejné až na záměnu módu z "w" (write) na "r" (read). Nyní budeme potřebovat pomocnou proměnnou, tzv. buffer, do kterého nám bude fscanf() řádku ukládat. Buffer se dělá dostatečně dlouhý, většinou 1024 znaků. Samotné čtení řádky je umístěno ve while cyklu a pokračuje dokud fscanf() nevrátí hodnotu EOF. Ta signalizuje, že jsme již dosáhli konce souboru. Formátovací řetězec je třeba upravit, jinak by se skenování zastavovalo o bílé znaky (mezery) a my nechceme, aby se zastavovalo jen na konci řádků (\n) a my tak četli najednou celé řádky. Načtenou řádku z bufferu vypíšeme a pokračujeme znovu. Na konci soubor uzavřeme.

Výsledek:

c_soubory_cteni
Drahá Brynn,
opatruj se, Malcolm unikl a jistě si pro mne brzy přijde jako pro prvního.
Musíš navést Brandona, dovést ho k amuletu, klíčem k zaříkávadlu by možná
mohla být levandulová růže.
Kallak

Funkce fscanf() má bohužel tu vlastnost, že spolyká prázdné řádky v souboru a my o nich ani nebudeme vědět. Někdy nás to netrápí, ale někdy bu nám to mohlo vadit. Proto se pro čtení ze souboru někdy používá funkce fgets(), která načte celý řádek až do konce. Abychom to neměli moc jednoduché, vrací funkce řádek i s jeho ukončením, tedy se znakem \n. Ten nám někdy nevadí (např. zde), ale někdy bychom ho museli odstraňovat. Pro použití fgets() by se while cyklus změnil na následující podobu:

while (fgets(buffer, sizeof(buffer), p_soubor) != NULL)
{
    printf("%s", buffer);
}

Výsledek:

c_soubory_cteni
Drahá Brynn,
opatruj se, Malcolm unikl a jistě si pro mne brzy přijde jako pro prvního.
Musíš navést Brandona, dovést ho k amuletu, klíčem k zaříkávadlu by možná
mohla být levandulová růže.

Kallak

Za zmínku stojí, že k funkci fgets() existuje i funkce fputs(), která do souboru zapíše celou řádku. Její výhodou je, že za ni automaticky dosadí \n a my ho už nemusíme připojovat. Možná vás napadlo, zda neexistují i funkce gets() a puts() pro standardní vstup a výstup. Ano, můžeme je používat místo printf() a scanf().

Připsání k souboru

Na konec si ještě ukažme, jak k existujícímu souboru něco připsat. Protože kód spočívá v podstatě jen v záměně mód "w" za "a" (append), kód si ani nemusíme vysvětlovat:

int main(int argc, char** argv) {
    // Otevření souboru pro připsání
    FILE * p_soubor = fopen("dopis.txt", "a");
    if (p_soubor == NULL)
    {
        printf("Soubor se nepodařilo otevřít pro připsání, zkontrolujte prosím oprávnění.");
        return 1;
    }

    // Zápis řádek do souboru
    fprintf(p_soubor, "\nPS: Vyžádej pomoc od Darma a Zanthie pro vybudování sil amuletu.\n");

    // Uzavření souboru
    if (fclose(p_soubor) == EOF)
    {
        printf("Soubor se nepodařilo uzavřít.");
        return 1;
    }

    return (EXIT_SUCCESS);
}

A když si otevřeme soubor v textovém editoru:

Připsání do textového souboru v jazyce C - Práce se soubory v jazyce C

Pokročilejší práce s textovými soubory (zejména parsování formátu CSV) je ukázána v článcích Evidence osob v jazyce C - Zadávání a ukládání osob do CSV a Evidence osob v jazyce C - Načítání a vyhledávání osob.

V příští lekci, Binární soubory a neformátovaný text v jazyce C, na nás čekají binární soubory.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 140x (108.97 kB)
Aplikace je včetně zdrojových kódů v jazyce C

 

Předchozí článek
Úvod do práce se soubory v jazyce C
Všechny články v sekci
Práce se soubory v jazyce C
Přeskočit článek
(nedoporučujeme)
Binární soubory a neformátovaný text v jazyce C
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
10 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity