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

C a C++ Céčko Práce se soubory Práce s textovými soubory (txt) v jazyce C

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

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

Č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

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, na nás čekají binární soubory.


 

Stáhnout

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

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
3 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Miniatura
Všechny články v sekci
Práce se soubory v jazyce C
Aktivity (4)

 

 

Komentáře
Zobrazit starší komentáře (1)

Avatar
ra3sk
Člen
Avatar
ra3sk:20.11.2015 21:33

Ahoj, používam MAC OS X a nejde mi práca so súborom.

 
Odpovědět  -2 20.11.2015 21:33
Avatar
Prasopes
Člen
Avatar
Odpovídá na ra3sk
Prasopes:24.12.2015 19:18

Ahoj, sedim v autě a netočí se mi kola.

 
Odpovědět  +4 24.12.2015 19:18
Avatar
Odpovídá na Prasopes
Michal Štěpánek:25.12.2015 0:41

Zkus vystoupit a nastoupit 8-)

Odpovědět  +1 25.12.2015 0:41
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Richard H.
Redaktor
Avatar
Odpovídá na ra3sk
Richard H.:25.12.2015 13:17

Když si takhle nekonkrétní tak ti nikdo nepomůže. Možná pokud napíšeš co to přesně hází za chybu tak bych ti možná byl schopen pomoct a když pošleš i kód co nefunguje tak to bude ještě lepší.

Odpovědět  +1 25.12.2015 13:17
Malý užitečný manuál je vždy lepší než bichle k ničemu.
Avatar
mkub
Redaktor
Avatar
Odpovídá na Richard H.
mkub:25.12.2015 15:07

mam pocit, ze je to znama firma, ktora rada tu dava podobne otazky, ako je tato...

 
Odpovědět 25.12.2015 15:07
Avatar
Lukáš Hypša:6. ledna 18:44

To čtení mi funguje jenom tehdy, když jsem do souboru zapisoval programem, ne normálně přes klávesnici.
Jak se čtou soubory, které psal někdo normálně přes klávesnici?

Odpovědět 6. ledna 18:44
Jsem lama co se roky snaží naučit napsat aspoň pár řádků a furt mu to nejde...
Avatar
Lukáš Hypša:7. ledna 14:23

Respektive, při zapsání programem se mi po otevření souboru nezobrazí odřádkování(na obrázku), když do souboru píšu manuálně tak se mi při čtení na začátku vypíše tečka uprostřed (v konzoli se vypíše otazník).

Odpovědět 7. ledna 14:23
Jsem lama co se roky snaží naučit napsat aspoň pár řádků a furt mu to nejde...
Avatar
Student C
Člen
Avatar
Student C:6. května 10:50

jak se načítá ze souboru když neznám množství částí txtu ?

např..... (rohlík,melou­n,jablko.....­......)
jak to načíst když načítám po čárku a neznám množství částí??????

nevíte pls?

 
Odpovědět 6. května 10:50
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Student C
DarkCoder:6. května 15:53

Soubory, kde hodnoty jsou odděleny čárkou, jsou označovány jako CSV soubory. CSV (comma-separated values, neboli hodnoty oddělené čárkou) je souborový formát určený pro práci s tabulkami.

Data v souboru jsou obvykle uskupena do jednotlivých řádků, což představuje souhrnné informace o konkrétní jednotce. Nemusíš znát počet řádků (nic ti však nebrání si tuto hodnotu poznamenávat). To co bys ale mě znát je počet položek, ze kterých se daná jednotka skládá. To abys mohl tyto dílčí položky řádně přiřadit a pracovat s nimi.

Představ si následující soubor:

Jablko, ovoce, 50, kg
Brokolice, zelenina, 20, kus
Kofola, nápoje, 25, kus
...

Položky jednotky představují Zboží, Kategorii, Cenu a Jednotku.
Uvedený příklad je hodně zjednodušený, demonstruje pouze způsob uložení dat v souboru.

Princip načítání dat je jednoduchý. Postupně načítám jednotlivé řádky na které provádím tokenizaci položek, které následně přiřazuji tam kam potřebuji.

Můžeš se setkat se soubory které jsou odděleny středníkem, popř. tabulátorem (TSV soubor). Princip načítání dat je obdobný. CSV databázové soubory jsou pro svoji jednoduchost v aplikacích velmi hojně používané a je bezpodmíněčně nutné umět s nimi pracovat.

Odpovědět 6. května 15:53
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Student C
Člen
Avatar
 
Odpovědět 7. května 13:33
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 11. Zobrazit vše