Lekce 6 - Rozdíly mezi textovými a binárními soubory v jazyce C
V minulé lekci, Manipulace se soubory a práce s errory v jazyce C, jsme se naučili další módy funkce
fopen()
a také pracovat s errory.
Dnešné, posledná lekcia, zhŕňa rozdiely medzi textovými a binárnymi súbormi.
Skôr ako sa pustíme do samotnej témy, bol by som rád, keby ste si nastavili IDE na normu C99 a aby ste písali čo najlepší kód, nastavili si compilátor tak, že každý warning sa zmení na chybu a compilátor vám nedovolí program scompilovať, kým to nenapravíte.
V Code:Blocks sa to nastavuje takto: Settings -> Compiler and debugger... -> Other options a tam do okna vložíte: -std=gnu99 -Werror -Wall -lm

V dnešnom článku si povieme prečo a v ktorých prípadoch je výhodné používať na ukladanie dát textové súbory a kedy binárne súbory.
Textové a binárne súbory
Textové súbory majú výhodu, že je možné kedykoľvek
si prehliadnuť ich obsah, vytvoriť ich alebo upraviť bežným editorom. To je
aj dôvod, prečo sú vhodné na ukladanie textu.
Na ukladanie iných dátových typov sa síce môžu použiť, ale nie je to
výhodné, pretože napríklad číslo 65535 zaberie v textovom súbore priestor
5 Byte a v binárnom len 2 Byte.
Ďalej nie sú vhodné na ukladanie polí, pretože medzi jednotlivé prvky
poľa ešte musíme vložiť nejaký separátor, napriklad medzeru a tým je
súbor automaticky väčší.
Binárne súbory majú nevýhodu, že síce si ich obsah
môžme prehliadnuť napríklad PSPad editorom, ale niečo v nich meniť je
prinajmenšom nevhodné, pretože môžeme viac pokaziť ako napraviť.
Výhodou je, že sú väčšinou menšie, rýchlejšie sa s nimi pracuje a pri
ukladaní polí nepotrebujú separátor.
Teraz si dokážeme to, čo som napísal.
Program
Napíšeme si jednoduchý program, ktorý najprv vytvorí pole 50 000 000 integerov. Potom to pole načíta do textového súboru a nakoniec ho načíta do binárneho súboru. Každému úkonu sa bude merať čas a nakoniec sa výsledky vypíšu.
Založme si nový Project Console application napríklad UlozenieTextBin. Pridajme si do projektu dva súbory, (source) fce.c a (header) fce.h. Súbor main.c sa vytvorí automaticky.
Najprv si v súbore fce.h zadeklarujeme potrebné funkcie a popíšeme ich:
/** fce.h **/ #ifndef FCE_H_INCLUDED // ak nie je súbor načítaný #define FCE_H_INCLUDED // načítaj súbor #define POCET 50000000 // počet prvkov poľa /** * Funkcia zapíše obsah poľa do textového súboru * @param pole premenných typu int * @param reťazec - názov súboru */ void vytvor_txt_subor(int pole[], char* subor); /** * Funkcia zapíše obsah poľa do binárneho súboru * @param pole premenných typu int * @param reťazec - názov súboru */ void vytvor_bin_subor(int pole[], char* subor); #endif // ukončenie podmienky preprocesora
Ďalej si v súbore fce.c deklarované funkcie zadefinujeme:
/** funkcie.c **/ #include <stdio.h> #include "fce.h" void vytvor_txt_subor(int pole[], char* subor) { FILE *fw; // deklarácia pointeru na dátový typ FILE fw = fopen(subor, "w"); // otvorenie textového súboru na zápis for (int i = 0; i < POCET; i++) // v cykle sa do súboru fw ukladajú fprintf(fw, "%d ", pole[i]); // integery s medzerou fclose(fw); // uzatvorenie súboru musí byť!!! } void vytvor_bin_subor(int pole[], char* subor) { FILE *fw; fw = fopen(subor, "wb"); // otvorenie binárneho súboru na zápis fwrite(&pole[0], sizeof(int), POCET, fw); // od adresy &pole[0] sa do súboru fw uloží POCET položiek o veľkosti sizeof(int) fclose(fw); // uzatvorenie súboru musí byť!!! }
Nakoniec upravíme súbor main.c:
/** main.c **/ #include <stdio.h> #include <stdlib.h> #include <time.h> #include "fce.h" int main() { int *pole1; // deklarácia pointera na pole integerov if ((pole1 = (int*)malloc(POCET * sizeof(int))) == NULL) { // dynamická alokácia pamäti s kontrolou printf("Malo pamati!"); return 1; } srand(time(0)); // inicializácia generátora náhodných čísiel printf("Vytvorim pole celych cisiel.\n"); clock_t start1 = clock(); // začiatok merania for (int i = 0; i < POCET; i++) // v cykle vložím do poľa pole1[i] = rand()%200000 + 100000; // náhodné čísla v rozsahu 10 000 - 200 000 clock_t finish1 = clock(); // koniec merania printf("Potrebny cas %.3f secund.\n", (float)((int)finish1 - (int)start1) / CLOCKS_PER_SEC); printf("\nZapisem pole do textoveho suboru.\n"); clock_t start2 = clock(); // začiatok merania vytvor_txt_subor(pole1, "test.txt"); // volanie funkcie clock_t finish2 = clock(); // koniec merania printf("Potrebny cas %.3f secund.\n", (float)((int)finish2 - (int)start2) / CLOCKS_PER_SEC); printf("\nZapisem pole do binarneho suboru.\n"); clock_t start3 = clock(); // začiatok merania vytvor_bin_subor(pole1, "test.dat"); // volanie funkcie clock_t finish3 = clock(); // koniec merania printf("Potrebny cas %.3f secund.\n", (float)((int)finish3 - (int)start3) / CLOCKS_PER_SEC); free(pole1); // uvolnenie pamäti vyčlenenej pre pole return 0; }
Keď project skompilujeme a spustíme dostaneme výstup:
UlozenieTextBin
Vytvorim pole celych cisiel.
Potrebny cas 2.470 secund.
Zapisem pole do textoveho suboru.
Potrebny cas 18.140 secund.
Zapisem pole do binarneho suboru.
Potrebny cas 0.490 secund.
Ako vidíte, rozdiel v čase zápisu do súborov je obrovský.
Veľkosť súborov:
test.txt

test.dat

Aj veľkosť súborov je veľmi rozdielna.
Doplníme náš program o načítanie textového a binárneho súboru do polí, samozrejme s meraním času.
Do súboru fce.h doplníme deklarácie nových funkcií:
/** * Funkcia prečíta obsah textového súboru a vloží ho do poľa * @param pole premenných typu int * @param reťazec - názov súboru */ void precitaj_txt_subor(int pole[], char* subor); /** * Funkcia prečíta obsah binárneho súboru a vloží ho do poľa * @param pole premenných typu int * @param reťazec - názov súboru */ void precitaj_bin_subor(int pole[], char* subor);
V súbore fce.c. in zadefinujeme:
void precitaj_txt_subor(int pole[], char* subor) { FILE *fr; int i = 0, j; fr = fopen(subor, "r"); while ((fscanf(fr, "%d", &j)) != EOF) { // v cykle číta integery zo súboru pole[i] = j; // a vkladá ich do poľa i++; } fclose(fr); } void precitaj_bin_subor(int pole[], char* subor) { FILE *fr; fr = fopen(subor, "rb"); fread(&pole[0], sizeof(int), POCET, fr); // od adresy &pole[0] vloží zo súboru POCET integerov do poľa fclose(fr); }
A nakoniec doplníme do súboru main.c nasledujúci kód:
int *pole2; if ((pole2 = (int*)malloc(POCET * sizeof(int))) == NULL) { printf("Malo pamati!"); return 1; } printf("\nPrecitam textovy subor do pola.\n"); clock_t start4 = clock(); // začiatok merania precitaj_txt_subor(pole2, "test.txt"); clock_t finish4 = clock(); // koniec merania printf("Potrebny cas %.3f secund.\n", (float)((int)finish4 - (int)start4) / CLOCKS_PER_SEC); int *pole3; if ((pole3 = (int*)malloc(POCET * sizeof(int))) == NULL) { printf("Malo pamati!"); return 1; } printf("\nPrecitam binarny subor do pola.\n"); clock_t start5 = clock(); // začiatok merania precitaj_bin_subor(pole3, "test.dat"); clock_t finish5 = clock(); // koniec merania printf("Potrebny cas %.3f secund.\n", (float)((int)finish5 - (int)start5) / CLOCKS_PER_SEC);
Aby sme znovu nespustili vytvorenie poľa a jeho zápis do súborov (súbory
by sa prepísali), zakomentujeme prvú časť v súbore main.c. Teda všetko čo
je nad riadkom
int *pole2;
Scompilujeme a môžme spustiť. Výstup je:
UlozenieTextBin
Precitam textovy subor do pola.
Potrebny cas 18.570 secund.
Precitam binarny subor do pola.
Potrebny cas 0.390 secund.
A zase vidíte obrovský rozdiel v časoch čítania jednotlivých
súborov.
To je pre dnešok všetko.
Projekt je napísaný v Code:Blocks na Ubuntu 10.04. Nedá sa otvoriť v Code:Blocks vo Windowse, ale jednotlivé súbory sa môžu skopírovať a bude to pracovať aj tam. Projekt je priložený.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 117x (12.09 kB)
Aplikace je včetně zdrojových kódů v jazyce C