Dátové objekty 3 - súbory


Obsah tém. 

  1. Dátový objekt - diskový súbor
    1. Základné operácie s diskovým súborom
  2. Práca s binárnymi súbormi
  3. Riadkovo orientovaný vstup/výstup z/do súboru
  4. Úlohy pre zopakovanie 

Dátový objekt - diskový súbor

Spôsobom, ako dlhodobo uchovávať dátové objekty, je ich uloženie na pamäťové médiá.  Prenos elektrických hodnôt z Operačnej pamäte na pamäťové médiá predstavujú druh transformácie elektrických veličín na mechanické alebo magnetické, niekedy aj ich kombinácie. 

Historicky prvé metódy boli uchovávania dát boli mechanické. Záznamy sa uskutočňovali do papierových štítkov alebo papierových pások vysekávaním mechanických dier. Neskôr ich nahradili magnetické médiá - drôty, pásky, štítky, bubny a konečne disky a pružné diskety vytváraný pomocou posúvanej magnetickej hlavy nad médiom. Šírka magnetickej hlavy limitovala šírku zaznamenávanej stopy nad plochou média.  
Neskôr prechodom na laserové lúče sa šírka záznamovej stopy výrazne zúžila a tým vzrástla kapacita. Optické systémy boli zvyčajne drahšie. Určitým kompromisom bola kombinácia magnetických technológií s optickými. Pri magneticko-optických metódach sa magnetická vrstva nahrievala optickým lúčom a na takto nahriatu stopu sa aplikovalo magnetické pole hlavy, ktorá pokrýva aj niekoľko tenkých stôp naraz. Takto sa kapacita lacnejšej magnetickej technológie  niekoľkonásobne zvyšila. Další vývoj optických technológií CD ROM, CD RAM, CD RW, DVD ,... a hlavne nárast frekvencií laserových signálov narastá ich kapacita pri súčasnom poklese cien, ale aj týmto technológiám, používajúcim mechanické komponenty, zvoní umieračik.  
Posledné metódy viac využívajú záznam elektrických veličín priamo do kremíkových pamätí - FLASH memory, resp. EEPROM. Ich kapacita výrazne vzrastá aj pri nízkej cene. Ich budúcnosť spočíva v spojení s optickými technológiami vstupu a výstupu cez optické vlákna.  

Nech už ide o hociaké médium všetky zaznamenané dáta vytvárajú dátový objekt nazývaný diskový súbor (pôvodne uchovávaný na diskete alebo pevnom disku). Zároveň nie je podstatné akým spôsobom sa dáta uchovávajú, dôležité len to že programy v C jazyku narábajú so súbormi rovnakým spôsobom. 

Hardwarový princíp súborov je postavený na blokoch rovnakej veľkosti (zvyčajne 512 bajtov). Jednotlivé bloky majú svoju hardwarovú adresu. Súbory sú vytvárané ako Hlavičkové bloky obsahujúce parametre súborov - názov, veľkosť, typ, ... a dátové bloky obsahujúce bajty súboru. Hlavičkové bloky v sebe obsahujú číslované zoznamy blokov obsahujúcich bajty súboru. Bloky sú nezávislé a správca súboru ich súborom prideľuje náhodne. Táto štruktúra je z hladiska programovania neviditeľná a jej organizovanie a správu zabezpečuje operačný systém. 

Pre program sa javí súbor ako súvislý priestor bajtov. Z historického hľadiska  sa dodnes delia súbory na textové a binárne. Textové súbory obsahujú 8 bitové  ASCII kódy, z ktorých 32 sú riadiacich a zvyšné (až do 255) sú "tlačitelné". Binárne súbory obsahujú netextové údaje ktorých štruktúru, obsah a použitie určujú jednotlivé aplikácie. Rozdelenie súborov je len formálne a aj na textový súbor môžeme nazerať ako na binárny. 

 

      Základné operácie s diskovým súborom

 Základné filozofia práce so súbormi spočíva v týchto detailoch:

  1. Súbory na diskoch sú organizované svojim názvom vyjadriteľné reťazcom. 

  2. Počas behu programu súbor bude predstavovať premenná typu FILE (súbor).

  3. Nad objektom FILE sa dajú vykonávať operácie:

    1. Otvor súbor

    2. Čítaj/Zapíš do súboru

    3. Zatvor súbor

         Defnícia súboru

Typ premennej FILE môžeme priraďovať  premenným, ktoré môžu predstavovať ľubovolný diskový súbor.

     FILE *fr, *fw;

Existujú dva špeciálne "súbory", ktoré nie sú lokalizované na pamäťovom médiu, ani nemá názov, a slúžia na vstup a výstup dát z klávesnice a na obrazovku. V stdio.h  sú tri definície konštantných pointrov:

 
     FILE *stdin ; // štandardný vstup - zvyčajne klávesnica
     FILE *stdout; // standardný výstup - zvyčajne obrazovka
     FILE *stderr; // štandarný výstup pre chybové hlásenia

Spomenuté "súbory" v UNIXE alebo DOSe sa dajú presmerovať do a zo súboru bez potreby zasahovať do programu. 
Príklad pre program vytlac.exe  v DOSe:     A:\ > vytlac    vypisuje na obrazovku ale príkaz  A:\ > vytlac > vystup.txt všetko presmeruje do súboru vystup.txt, ktorý sam vytvorí, otvorí a na konci uzatvorí. DOS obsahuje ešte dva štandardné výstupy:

 
     FILE *stdaux; // sériové rozhranie
     FILE *stdprn; // standardný paralelný výstup - zvyčajne tlačiareň
     

Vstup a výstup stdin a stdout sa dajú použiť vo funkciách pracujúcich so súbormi:

 
     getc(stdin) ;   // odpovedá getchar();
     putc(c,stdout); // odpovedá putchar(c);

 

        Otvorenie súboru

Počiatočná operácia na začiatku práce so súborom je vždy otvorenie súboru. Tu je prototyp funkcie:

     FILE *fopen(const char * meno, const char *rezim);

Kľúčové slovo  const v deklarácii znamená, že údaje sa nebudú meniť, a tak ako sa použijú v tejto funkcii budú predstavovať len vstupné údaje.  

Režim môže nadobúdať tieto hodnoty:

  r    (rt) - textový súbor len čítanie (v zátvorke explicitné vyjadrenie)
  w  (wt) - textový súbor určený pre zápis alebo prepísanie
  a   (at) - textový súbor v ktorom budeme pripájať na koniec
  rb - binárny súbor určený na čítanie
  wb - binárny súbor určený pre zápis alebo prepísanie
  ab - binárny súbor v ktorom budeme pripájať na koniec
  r+ - textový súbor určený na čítanie a zápis
  w+ - textový súbor určený pre čítanie, zápis alebo prepísanie
  a+ - textový súbor určený na čítanie a zápis na koniec
  rb+ - binárny súbor určený na čítanie a zápis
  wb+ - binárny súbor určený pre čítanie, zápis alebo prepísanie
  ab+ - binárny súbor určený na čítanie a zápis na koniec
  1. Otvorenie súboru v režime w, alebo wb spôsobí vymazanie predošlej existencie tohto súboru a potom opätovné nové založenie.
  2. Otvorenie existujúceho súboru v režime a, alebo ab, spôsobí presunutie kurzora na koniec súboru a prípravu na dopisovanie na konci. Ak súbor neexistoval je otvorený nový prázdny súbor a kurzor je na začiatku.
  3. Súbory otvorené so znakom + sú určené pre čítanie aj zápis, ale má význam len u binárnych súborov.
  4. Na rozdiel od DOSu a WINDOWSu UNIX ukončuje riadky jediným znakom '\n' (< LF > = 0Ah) pred ktorým v DOSe a WIN..Se  je '\r' (< CR > = 0Dh). V UNIXe je zbytočné označenie súboru - textový alebo binárny t.j. t a b vo výraze "wb". 

Príklad súborov otváraných buď na čítanie alebo na zápis.  

     fr=fopen("POKUS","rt");  // otvorenie na čítanie r- read t- text
     fr=fopen("POKUS","rb");  // otvorenie na čítanie r- read b- binary
     fw=fopen("POKUS","wt");  // otvorenie súboru na zápis w- write t-text
     fw=fopen("POKUS","wb");  // otvorenie súboru na zápis w- write b-binary

         Základné operácie so súborom

Súbory fr otvorený na čítanie a fw otvorený na zápis. 

     c=getc(fr);                     // citanie znaku zo súboru
     putc(c,fw);                     // zápis znaku do súboru
     fscanf(fr,"format",argumenty);  // formátované čítanie zo súboru
     fprintf(fw,"format",argumenty); // formátovaný zápis do súboru

Poznamka: analogické operácie.

     c=getchar();                    // citanie znaku z klávesnice
     putchar(c);                     // zápis znaku na obrazovku
     scanf("format",argumenty);      // formátované čítanie z klávesnice
     printf("format",argumenty);     // formátovaný zápis na obrazovku

        Zatvorenie súboru

Súbor otváraný buď na čítanie alebo na zápis.  

     fclose(fw);   // zatvorenie súboru
     

 Príklad: Vytvoríme súbor POKUS.TXT a zapíšeme doň čísla od 1 do 10

#include < stdio.h >

void main(void)
{
  FILE *fw;
  int i;
 
  fw= fopen("POKUS.TXT","w"); 
  for (i=1; i<10 ; i++) 
     fprintf(fw,"%d \n",i);

  fclose(fw);
  }

 

Príklad: Program prečíta tri double čísla zo súboru DATA.TXT a vypíše na obrazovku ich súčet. 

#include < stdio.h >

void main(void)
{
  FILE *fr;
  double x,y,z;
 
  fr= fopen("DATA.TXT","r"); 
  if (fscan(fr,"%lf %lf %lf",&x,&y,&z)==3) 
     printf("%f \n",x+y+z);
  else
     printf("Súbor DATA.TXT neobsahuje 3 reálne čísla \n");

  fclose(fr);
  }

Príklad: Program prečíta dva znaky zo súboru ZNAKY.TXT a zapíše ich do súboru KOPIA.TXT. 

#include < stdio.h >

void main(void)
{
  FILE *fr, *fw;
  int c;                     // znaky načítame do int premennej koli testu EOF==-1
 
  fr= fopen("ZNAKY.TXT","r"); 
  fw= fopen("KOPIA.TXT","w");

  if ( (c=getc(fr))!=EOF )   // test na koniec súboru
     putc(c,fw);
  putc(getc(fr),fw);

  fclose(fr);
  fclose(fw);
  }

 

Príklad: Program prečíta jeden riadok z  DOPIS.TXT a vypíše na obrazovku včítane znaku \n. 

#include < stdio.h >

void main(void)
{
  FILE *fr;
  int c;
 
  fr= fopen("DOPIS.TXT","r"); 
  while ((c=getc(fr)) != '\n') putchar(c);
  putchar(c);                 // vypíše aj \n
     
  fclose(fr);
  }

 

       Riadkovo orientovaný vstup/výstup z/do textového súboru

        Čítanie riadku z textového súboru

Načítanie riadka zo súboru sa uskutočňuje prototyp funkcie fgets(), ktorý číta zo súboru fr až do konca riadka nanajvýš max znakov včítane znaku '\n', a uloží ho do str. Funkcia vracia pointer na str, alebo pri dosiahnutí konca súboru vráti NULL. 

     char *fgets(char * str, int max, FILE * fr);

Poznámky:

  • Správne prečíta aj posledný riadok neukončený znakom  '\n',
  • Nakoľko fgets() vie určiť aj veľkosť načítavaného riadka, môže sa použiť pre načítavanie z terminálu: fgets(s,max,stdin); 
  • Po načítaní znaku End-Of-File tento sa zvyčajne nenačíta. 

Príklad:

Program prečíta obsah súboru DOPIS.TXT po riadkoch a vypíše jeho obsah na displej. Dĺžka načítavaného riadka je obmedzená na 80 znakov. 

#include < stdio.h >

int main(void)
{
  char riadok[80];
  FILE *fr;

  if ((fr=fopen("DOPIS.TXT","r"))==NULL)
  {
    printf("Súbor DOPIS.TXT sa nedá otvoriť \n");
    return;
    } 

  while(fgets(riadok,80,fr)!=NULL) printf("%s",riadok);

  if (fclose(fr)==EOF)
    printf("Súbor DOPIS.TXT sa nedá uzatvoriť  \n");
  }

        Zápis riadka do súboru

Ak chceme zapísať reťazec do súboru a neodriadkovať (odriadkovanie je v reťazci), potom použijeme funkciu fputs(), ktorá má nasledovný prototyp:

     int  fputs(char * str, FILE * fw);

Funkcia po zápise reťazca neodriadkuje ani nezapisuje do súboru ukončovací znak reťazca  '\0'. Jej návratová hodnota je nezáporné číslo. V prípade neúspechu vracia EOF. 

 

       Práca s binárnymi súbormi

      Rozdiel pri spracovaní textových a binárnych súborov v DOSe.

Práca s binárnymi súbormi sa od textových líši v niektorých detailoch a podrobne sa tým zaoberá nasledovná kapitola. Rozdiel spočíva v tom, ako zápis a čítanie ovplyvňujú funkcie zápisu a čítania do textového súboru. V DOSe pri zápise znaku  '\n' (0Ah) systém pred neho automaticky umiestni '\r' (0Dh). Pri čítaní z textového súboru sa poskytne jedine znak  '\n', a znak '\r' sa automaticky vyradí (zožerie). Funkcie určené na prácu so súbormi nekontrolujú a akým súborom pracujú (či s textovým alebo binárnym). To môže spôsobiť zlú interpretáciu obsahu pri použití funkcií fprintf(), fscanf(), getc(), putc(), ... 

Príklad:  zapíšme nasledovné znaky do súboru  'a','\n','b','\r','c','\n','\r','d', ktorým zodpovedajú kódy 61 0A 62 0D 63 0A 0D 64. Pri režime zápisu "w" pomocou putc('...',subor)  obdržíme nasledovný obsah 61 0D 0A 62 0D 63 0D 0A 0D 64. T.j. všade tam, kde sa zapisuje '\n', sa automaticky doplnila dvojica 'b' '\n' (0D 0A). Pri výpise pomocou "r" pre čítanie textov dostaneme 61 0A 62 63 0A 64 - t.j. odstránili sa všetky kódy '\r' (0D) z textu. Pri výpise "rb" dostaneme identický - nezmenený - obsah ako bol nájdený v súbore t.j. 61 0D 0A 62 0D 63 0D 0A 0D 64. Naopak pri zápise do súboru "wb" dostaneme identický súbor s originálom  61 0A 62 0D 63 0A 0D 64. Pri spätnom binárnom výpise "rb" dostaneme identický výpis s obsahom súboru t.j. 61 0A 62 0D 63 0A 0D 64, ale pri výpise ako textový súbor "r" dostaneme výpis zbavený kódov '\r' (0D) z textu 61 0A 62 63 0A 64.

Textové súbory sú hlavne určené pre uchovávanie písaných dokumentov písaných pomocou textových editorov. Jednotlivé písmená sa uchovávajú ako 8 bitové (1 bajtové)  ASCII kódy, ktoré sa v prípade potreby dajú priamo odoslať na tlačiareň ktorá vymení ASCII kódy za ich grafickú reprezentáciu na papieri. Hlavné operácie s nimi sú výpisy po znakoch, výpisy po riadkoch, vypisovanie od začiatku alebo dopisovanie na koniec. Aj v prípade dopisovania textu do stredu súboru, dá sa tento vykonať tak, že sa najprv opíše originál textu po určené miesto do nového pomocného súboru, nový text sa doplní z klávesnice na aktuálny koniec pomocného súboru, a nakoniec sa z originálu opíše zvyšok na koniec pomocného súboru. Pri ukončení "modifikácie" (úpravy) originálu sa nakoniec originál zruší (niekedy sa uloží do záložného súboru zakončeného  *.bak ) a pomocný súbor sa premenuje názvom zrušeného originálu. 

Binárne súbory sú zvyčajne určené na uchovávanie dát v ich vnútornej forme tak, ako sa nachádzajú aj v operačnej pamäti v násobkoch bajtov. Na rozdiel od textových súborov niektoré údaje sa nachádzajú v štrukturovaných  formách a zaberajú viac bajtov, ktoré sa prečítajú alebo zapisujú do súboru ako jeden "záznam" - (record). Na rozdiel od textových súborov - binárne súbory umožňujú vyhľadať časť súboru a prečítať obsah, potom tento upraviť a znova ho zapísať na rovnakú pozíciu do súboru. Tieto operácie vyžadujú špeciálne vyhľadávacie funkcie o ktorých bude reč. 

   Čítanie a zápis do binárneho súboru.

 

   Pohyb v binárnom súbore.

 

   Príklad použitia binárneho súboru.

       

Tu budem ešte doplňovať ...

Príklad č._ _  :
Program, ktorý načíta z klávesnice n desatinných čísel a vypíše ich v obrátenom poradí a načítanom poradí. Kód \n pri vypisovaní znamená - prejdi na nový riadok.

#include<stdio.h>
#include<conio.h>

void main(void)      // void - znamená "žiaden typ - žiadna premenná"
{
   ...
   }

Tu budem ešte doplňovať ...

Úlohy pre zopakovanie

  1. N................
        1. x........
        2. v...
        3. u....
        4. v.....
  2. N.....
  3. N.....
        1. v....
        2. u...
        3. v....
        4. v.....
  4. N.....