12. cvičení

Práce se soubory

Pro práci se soubory v jazyce C slouží struktura FILE a několik funkcí definovaných v hlavičkovém souboru stdio.h:

Při otevírání souboru je potřeba specifikovat, jestli chceme daný soubor otevřít pouze pro čtení, nebo pouze pro zápis. (Kombinace čtení a zápisu ve stejném souboru je sice možná, ale komplikovaná, takže se jí nebudeme zabývat.) Soubor pro zápis můžeme otevřít např. takto:

FILE* soubor = fopen("text.txt", "w");
if (soubor == NULL) {
    printf("chyba otevreni souboru\n");
    return 1;
}

Soubor pro čtení se otevře stejně, ale místo řetězce "w" se použije "r".

Po skončení práce s daným souborem je potřeba zavolat funkci fclose pro zavření souboru:

fclose(soubor);

Pokud bychom na zavření souboru zapomněli, nedošlo by k uvolnění alokované paměti a složitější programy by kvůli tomu mohly skončit chybou, protože každý operační systém má nějaký limit na počet otevřených souborů.

Zápis do souboru

Pro zápis dat do souboru je nejjednodušší použít funkci fprintf, která funguje v podstatě stejně jako funkce printf, pouze první parametr je ukazatel na soubor, kam se má text zapsat:

fprintf(soubor, "Hello, world!\n");

Pro zápis jediného znaku je možné použít funkci fputc (analogie k funkci putchar):

fputc(znak, soubor);

Čtení ze souboru

Pro čtení dat ze souboru existuje funkce fscanf, která funguje v podstatě stejně jako funkce scanf, pouze první parametr je ukazatel na soubor, ze kterého se má číst:

fscanf(soubor, "%d", &cislo);

Pro čtení textu však platí stejná poznámka, jako pro funkci scanf. Proto je lepší text ze souborů načítat ručně znak po znaku, k čemuž slouží funkce fgetc (analogie k funkci getchar). Funkci getLine z minulého cvičení můžeme upravit pro čtení ze souboru takto:

// funkce pro nacteni jednoho radku textu ze souboru
bool fgetLine(FILE* soubor, char* string, int maxDelka)
{
    for (int i = 0; i < maxDelka; i++) {
        // precti znak z terminalu
        int znak = fgetc(soubor);

        // kontrola jestli nedoslo k chybe cteni
        if (ferror(soubor)) {
            printf("Chyba: neslo precist cely radek\n");
            return false;
        }

        // zkontroluj, jestli neni konec vstupu
        if (znak != EOF && znak != '\n')
            string[i] = znak;
        else {
            // konec vstupu - ukonci string a prerus cyklus
            string[i] = '\0';
            return true;
        }
    }

    // v cyklu jsme nedosli ke znaku EOF ani k '\n' - radek je delsi nez (maxDelka - 1)
    // (vypisujeme maxDelka - 1, protoze posledni znak musi byt '\0', ktery ale uzivatel nezadava)
    printf("Chyba: radek je delsi nez maximalni povolena delka %d znaku.\n", maxDelka - 1);
    return false;
}

Oproti funkci getLine zde navíc pomocí funkce ferror kontrolujeme, jestli nedošlo k chybě čtení. Také existuje funkce feof, která kontroluje, jestli jsme došli na konec souboru (hodí se hlavně v kombinaci s funkcí fscanf).

Důležité poznámky

Probrané příklady

  1. Program demonstrující základní práci se soubory (viz jednotlivé příkazy výše).
  2. Různé způsoby načítání textu ze souboru:
    • znak po znaku (cyklus s funkcí fgetc)
    • řádek po řádku (cyklus s funkcí fgetc a ukončení znakem '\n', viz funkce fgetLine výše)
    • slovo po slovu (cyklus s funkcí fgetc, přeskočení všech prázdných znaků na začátku a ukončení libovolným prázdným znakem)
  3. Program pro určení délky nejdelšího slova a počtu slov v textovém souboru (modifikace programu z předchozího cvičení).
  4. Program, který přečte text ze souboru a slovo z terminálu, vyhledá zadané slovo v textu, přepíše všechny výskyty tohoto slova v textu velkými písmeny a výsledný řetězec zapíše do jiného souboru.