Seminář 10

Binární režim

Čteme a zapisujeme bajty, které při čtení nejsou nijak interpretovány.

Funkce pro čtení

size_t fread(void *dest, size_t element_size, size_t count, FILE *in)

Čteme count prvků, každý o velikost element_size bajtů, ze streamu in, ukládáme je do pole na adrese dest. Vrací počet přečtených prvků, pokud bylo čtení bez chyby, pak se count a návratová hodnota rovnají. Je nutné myslet na to, že na adrese dest musí být naalokováno dostatek paměti, jinak dojde k nedefinovanému chování.

Funkce pro zápis

size_t fwrite(void *src, size_t element_size, size_t count, FILE *out)

do streamu out zapise count položek, každy o velikosti element_size uložených za sebou na adrese src. Funkce vrací počet zapsaných položek.

Můžeme také pracovat s akturální pozicí, ze které v souboru čteme. Pozice je hodnota typu long a je to index bajtu od začátku. Aktuální pozici můžeme získat pomocí funkce

long ftell(FILE* stream)

Aktuální pozici také můžeme nastavit pomocí funkce

int fseek(FILE *stream, long offset, int start)

kde offset je počet bajtů, o které se chceme posunout a start určuje místo, ze kterého se chceme posunout. Pro tento účel jsou definovány konstanty

SEEK_SET zacatek souboru
SEEK_CUR aktualni pozice
SEEK_END konec souboru

V následujícím příkladu zapíšeme do souboru a zase načteme pole.

char *filename = "tmp.xx";

// zapis do souboru

float out_array[4] = { 1.0f, 2.0f, 3.0f, 4.0f };
    
FILE *out = fopen(filename, "wb");
assert(out);

size_t written = fwrite(out_array, sizeof(float), 4, out);
assert(written == 4);

fclose(out);

    
// cteni ze souboru, od druheho prvku
FILE *in = fopen(filename, "rb");
// posuneme se o jeden float dopredu
int fail = fseek(in, sizeof(float), SEEK_SET);
assert(!fail);

float in_array[3]= { 0.0f, 0.0f, 0.0f };
size_t read = fread(in_array, sizeof(float), 3, in);
assert(read == 3);
fclose(in); 
    
for(int i = 0; i < 3; i += 1) {
    printf("%f ", in_array[i]);
}
printf("\n");

Práce s binárními soubory a čtení binárních formátů má svá specifika, musíme si dávat pozor na velikosti typů, endianitu apod.

Úkoly

  1. Uvažeme ukládání řetězců do souboru v binárním formátu.

    Naprogramujte funkci void append(char* string, char* filename), která na konec souboru přidá nový řetězec.

    Naprogramujte funkci long search(char* string, char* filename), která prohledá soubor a pokud obsahuje záznam o daném řetězci, vrátí jeho offset od začátku souboru. Jinak vrátí -1.

    V souboru odpovídá řetězci jeden záznam, záznamy jsou v souboru za sebou. Jeden záznam vypadá následovně.

   offset  velikost   vyznam
   --------------------------------------------------------------------------
    0       2          velikost retezce v bajtech

    2       ?          ulozeny retezec, chapan jako posloupnost unsigned char
                       bez 0 na konci
   --------------------------------------------------------------------------