Zápis do souboru

Pokud chceme do otevřeného souboru zapsat nějaké byty, můžeme použít funkci fwrite:

size_t fwrite(
    const void* buffer, // adresa, ze které načteme data do souboru
    size_t size,        // velikost prvku, který zapisujeme
    size_t count,       // počet prvků, které zapisujeme
    FILE* stream        // soubor, do kterého zapisujeme
);

Funkce fwrite předpokládá, že budeme do souboru zapisovat více hodnot stejného datového typu. Parametr size udává velikost tohoto datového typu a parametr count počet hodnot, které chceme zapsat. Pokud tuto funkci zavoláme, tak dojde k zápisu size * count bytů z adresy buffer do souboru stream. Návratová hodnota fwrite značí, kolik prvků bylo do souboru úspěšně zapsáno. Pokud je tato hodnota menší než count, tak došlo k nějaké chybě. Například zápis pěti celých čísel do souboru by mohl vypadat následovně:

#include <stdio.h>
#include <assert.h>

int main() {
    int pole[5] = { 1, 2, 3, 4, 5 };

    // otevření souboru
    FILE* soubor = fopen("soubor", "wb");
    assert(soubor);

    // binární zápis do souboru
    int zapsano = fwrite(pole, sizeof(int), 5, soubor);
    assert(zapsano == 5);

    // zavření souboru
    fclose(soubor);    

    return 0;
}

Při takovémto použití fwrite může dojít k zapsání například pouze 3 čísel, pokud během zápisu dojde k chybě1. Pokud bychom chtěli zapsat buď vše nebo nic, můžeme říct, že zapisujeme pouze jeden prvek a parameter count nastavit na celkovou velikost všech dat, které chceme zapsat:

1V takovémto případě by funkce fwrite vrátila hodnotu 3.

int pole[5] = { 1, 2, 3, 4, 5 };
fwrite(pole, sizeof(pole), 1, soubor);

Pokud bychom zapsali pole do souboru takto, uloží se do něj celkem 20 (5 * 4) bytů (čísel), které později můžeme v programu zase načíst zpátky. Pokud bychom se podívali, co v souboru je, nalezli bychom seznam čísel 1 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0, což odpovídá paměťové reprezentaci pole pěti intů, které bylo vytvořeno výše.

Textový zápis

Pokud bychom chtěli tato data zapsat do souboru v textové podobě (a ne pouze jako jejich binární reprezentaci), můžeme čísla z výše zmíněného pole zapsat pomocí nějakého textového kódování, například ASCII. K tomu můžeme využít funkci fprintf, která funguje stejně jako printf, s tím rozdílem, že text nevypisuje na stdout, ale do předaného souboru2:

2Všimněte si, že zde jsme použili mód otevření pro textový zápis ("wt"), namísto binárního zápisu "wb" použitého výše.

#include <stdio.h>
#include <assert.h>

int main() {
    int pole[5] = { 1, 2, 3, 4, 5 };

    // otevření souboru
    FILE* soubor = fopen("soubor.txt", "wt");
    assert(soubor);

    // textový zápis do souboru
    for (int i = 0; i < 5; i++) {
        fprintf(soubor, "%d ", pole[i]);
    }

    // zavření souboru
    fclose(soubor);    

    return 0;
}

V tomto případě by se do souboru zapsalo deset bytů (čísel) 49 32 50 32 51 32 52 32 53 32, protože číslice jsou v ASCII reprezentovány čísly 4857 a mezera je reprezentována číslem 32. Pokud bychom tento soubor otevřeli v textovém editoru, tak by se nám zobrazil text 1 2 3 4 5 .

Bufferování

Stejně jako při zápisu do stdout se i při zápisu do souborů uplatňuje bufferování. Data, která do souboru zapíšeme, se tak v něm neobjeví hned. Pokud bychom chtěli donutit náš program, aby data uložená v bufferu opravdu vypsal do souboru, můžeme použít funkci fflush 3.

3Ani zavolání funkce fflush však nezajistí, že se data opravdu zapíšou na fyzické médium (například harddisk). To je ve skutečnosti velmi obtížný problém.