2. diel - Práca s textovými súbormi (txt) v jazyku C
V minulej lekcii, Úvod do práce so súbormi v jazyku C , sme si urobili úvod do práce so súbormi. V dnešnom C tutoriálu sa naučíme pracovať s textovými súbormi, ktoré sú najjednoduchšie a tiež je asi budeme využívať najčastejšie. Do textových súborov zapisujeme alebo je čítame po riadkoch. Možno je samozrejme čítať / zapisovať i po znakoch, ale riadkový prístup je určite ľudskejší. K zápisu do súboru budeme používať funkciu fprintf () a na čítanie fscanf (). Dvojica funkcií funguje úplne rovnako ako printf () a scanf (), ktoré pracovali so štandardným vstupom / výstupom (konzol). Tieto funkcie však pracujú so súborom. Odkaz na súbor odovzdáme vždy ako prvý parameter funkcie.
Otvorenie súboru
Predtým, než sa súborom začneme pracovať, musíme ho otvoriť. K tomu slúži funkcia fopen (). Pri otváraní súboru špecifikujeme mód, pre ktorý súbor otvárame. Najčastejšie je to "w" (zápis), "r" (čítanie) alebo "a" (pripisovania).
Zatvorenie súboru
Po dokončení práce so súborom ho treba zatvoriť. Asi by ste uhádli, že na to slúži funkcia fclose (). Ak by sme súbor zabudli zavrieť, chápal by operačný systém ako že s ním stále pracujeme. Ostatné programy by ho nemohli používať a tiež by sme zbytočne plytvali zdrojmi, pretože operačný systém má na počet naraz otvorených súborov väčšinou nejaké limity. V neposlednom rade by sme si mali povedať, že práca so súbormi používa tzv. Buffer. Zapisovať totiž znak po znaku by disk veľmi vytížilo, preto sa čaká, až sa naplní určitá vyrovnávaciu pamäť, ktorá sa potom naraz na disk zapíše a tým sa ušetrí prístupy k disku. Keby sme zabudli zavolať fclose (), mohol by vo vyrovnávacej pamäti zostať ešte nejaký text, ktorý by sa do súboru nedopsal.
Zápis do súboru
Uveďme si konečne príklad a to vytvorenie jednoduchého textového súboru s listom. Čoskoro si ho vysvetlí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čiatku zavoláme funkciu fopen (), ktoré oznámime, že chceme otvoriť súbor dopis.txt v móde pre zápis. Ak súbor neexistuje, bude vytvorený. Ak už existuje, bude prepísaný! Funkcia vracia ukazovateľ na štruktúru typu FILE. Práve cez tento ukazovateľ budeme so súborom ďalej pracovať a preto si ho uložíme.
Súbor sa nemusí podariť otvoriť a to hlavne vtedy, keď k nemu nemá program prístup. Stane sa tak, keď program napr. Spustíme z disku CD, kam sa nedá zapisovať, alebo keď ho spustíme napr. Priamo na disku C (mimo užívateľské zložky ako sú dokumenty alebo plocha, kam máme povolené zapisovať). Pri tejto situácii vráti NULL (teda prázdny ukazovateľ) a na túto hodnotu by sme mali reagovať.
Prostredná časť programu je triviálne, iba zapisujeme do súboru riadky textu pomocou fprintf (). Samozrejme by sme mohli zapisovať napr. Aj premenné a to takto:
int hlasitost = 100; fprintf(p_soubor, "hlasitost=%d", hlasitost);
Rovnako, ako sa nemusí podariť otvorenie súboru, nemusí sa podariť ani jeho uzavretie. Funkcia fclose () v tomto prípade vráti hodnotu EOF (ako End Of File).
Keď aplikáciu spustíme, vytvorí sa v aktuálnej zložke s programom súbor dopis.txt s nasledujúcim obsahom:
Čítanie zo súboru
Čítanie zo súboru je veľmi podobné. Napíšeme si opačnú aplikáciu, ktorá list načíta a vypíše na obrazovku. Budeme predpokladať, že nevieme, koľko má riadkov a preto si ukážeme ako načítať všetky riadky zo súboru.
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); }
Otvorenie súboru je rovnaké až na zámenu módu z "w" (write) na "r" (read). Teraz budeme potrebovať pomocnú premennú, tzv. Buffer, do ktorého nám bude fscanf () riadku ukladať. Buffer sa robí dostatočne dlhý, väčšinou 1024 znakov. Samotné čítanie riadky je umiestnené vo while cyklu a pokračuje až kým fscanf () nevráti hodnotu EOF. Tá signalizuje, že sme už dosiahli konca súboru. Formátovací reťazec je potrebné upraviť, inak by sa skenovanie zastavovalo o biele znaky (medzery) a my nechceme, aby sa zastavovalo len na konci riadkov (\ n) a my tak čítali naraz celé riadky. Načítanú riadku z bufferu vypíšeme a pokračujeme znova. Na konci súbor uzavrieme.
výsledok:
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
Funkcia fscanf () má bohužiaľ tú vlastnosť, že prehltne prázdne riadky v súbore a my o nich ani nebudeme vedieť. Niekedy nás to netrápi, ale niekedy bu nám to mohlo vadiť. Preto sa pre čítanie zo súboru niekedy používa funkcie fgets (), ktorá načíta celý riadok až do konca. Aby sme to nemali moc jednoduché, vracia funkcia riadok aj s jeho ukončením, teda so znakom \ n. Ten nám niekedy nevadí (napr. Tu), ale niekedy by sme ho museli odstraňovať. Na použitie fgets () by sa while cyklus zmenil na nasledujúce podobu:
while (fgets(buffer, sizeof(buffer), p_soubor) != NULL) { printf("%s", buffer); }
výsledok:
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 zmienku stojí, že k funkcii fgets () existuje aj funkcia fputs (), ktorá do súboru zapíše celú riadku. Jej výhodou je, že za ňu automaticky dosadí \ na my ho už nemusíme pripájať. Možno vás napadlo, či neexistujú aj funkcia gets () a puts () pre štandardný vstup a výstup. Áno, môžeme ich používať namiesto printf () a scanf ().
Pripísanie k súboru
Na koniec si ešte ukážme, ako k existujúcemu súboru niečo pripísať. Pretože kód spočíva v podstate len v zámene mód "w" za "a" (append), kód si ani nemusíme vysvetľovať:
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 keď si otvoríme súbor v textovom editore:
Pokročilejšie práce s textovými súbormi (najmä parsovanie formáte CSV) je ukázaná v článkoch Evidencia osôb v jazyku C - Zadávanie a ukladanie osôb do CSV a Evidencia osôb v jazyku C - Načítanie a vyhľadávanie osôb.
V budúcej lekcii, Binárne súbory a neformátovaný text , na nás čakajú binárne súbory.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 143x (108.97 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C