LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (24) - Soubory

Dnes probereme operace se soubory. Ukážeme si, jak naprogramovat zjednodušené vlastní verze příkazů cat a cp.

15.9.2005 06:00 | Jan Němec | Články autora | přečteno 61747×

Soubory

Funkce pro základní operace se soubory nalezneme ve standardní knihovně jazyka C. Podobně jako v případě terminálového vstupu a výstupu musíme inkludovat stdio.h. C rozlišuje soubory textové a binární (obecné) a pro oba typy nabízí odlišnou sadu funkcí. Ve skutečnosti je z hlediska každého normálního operačního systému obsah běžného souboru jen N-tice bytů a to, zda se jedná o soubor textový nebo binární, je jen vlastností režimu práce s ním. V textovém režimu se díváme na jeho obsah jako na textová data, s tím, že některé znaky nebo jejich sekvence mají speciální význam, jde například o odřádkování, tabelátor nebo znak konce souboru. Konkrétní sada a interpretace těchto sekvencí pak závisí na operačním systému, proto například unixový textový soubor vypadá po otevření v notepadu ve Windows jako jedna dlouhá řádka s vloženými nezobrazitelnými znaky v místech původních konců řádek.

Soubor, který obsahuje pouze textová data, je zpravidla výhodnější zpracovávat v C v textovém režimu, ve výjimečných případech (například právě pokud chceme na Linuxu generovat soubor čitelný v notepadu) však použijeme i na textové soubory binární režim. Naproti tomu na soubor s jiným než textovým obsahem použít textový režim sice také můžeme, ale rozumný smysl to nemá.

Textový režim

Nejjednodušším smysluplným příkladem je výpis textového souboru na standardní výstup. Následující program je ekvivalentem příkazu

cat /etc/passwd
#include <stdio.h>

int main(void) {
  FILE *fr;
  char s[1024];
  
  fr = fopen("/etc/passwd", "r");
  if (!fr) {
    fputs("Nemohu otevřít vstupní soubor.\n", stderr);
    return 1;
  }
  while (fgets(s, sizeof(s), fr) != NULL) {
    fputs(s, stdout);
  }
  fclose(fr);
  return 0;
}

Pro soubory se ve standardní knihovně používají proměnné typu ukazatel na FILE, což je strukturovaný typ, ale jeho konkrétní položky nás nemusejí zajímat, slouží pro vnitřní potřebu runtime podpory jazyka C, programátor pracuje pouze s ukazatelem na celou strukturu. První operace je otevření souboru /etc/passwd. Funkce fopen vrací ukazatel na FILE - otevřený soubor, prvním parametrem je jeho jméno a druhým režim práce, v našem případě "r" znamená textový soubor otevřený pro čtení. Otevření souboru se nemusí podařit, proto je třeba otestovat návratovou hodnotu. Funkci fgets už známe z dílu o standardním vstupu, jedná se o čtení ze souboru fr řádky maximální délky sizeof(s) do bufferu s. Pokud je řádka delší, funkce přečte jen její začátek a případné další čtení ze souboru pomocí funkce fgets začne na místě, kde původní volání skončilo. I zde návratová hodnota NULL znamená neúspěch, například konec souboru. Funkce fputs je obdoba puts, pouze se píše do souboru. V našem případě je ovšem oním souborem stdout, tedy standardní výstup. Podobně můžeme používat i proměnné stdin a stderr se zřejmým významem. Rozdíl mezi puts(s) a fputs(s, stdout) je pouze v tom, že puts ještě navíc kromě výpisu řetězce odřádkuje, což se nám teď nehodí, neboť řetězec s již obsahuje znak nového řádku. Po ukončení práce se souborem je třeba jej zavřít funkcí fclose. Důležité je to především v případě zápisu, neboť teprve fclose vyprázdní buffery standardní C knihovny a fyzicky data uloží. Po čtení ze souboru voláme fclose "jen" z důvodu šetření systémových prostředků a programátorské slušnosti.

Funkcí pro práci se soubory v textovém režimu je více a většinou jim (názvem i chováním) odpovídá nějaké funkce pro práci se standardním vstupem a výstupem, kterou jsme si již popsali v počátečních dílech našeho seriálu.

FILE *fopen(const char *path, const char *mode);

Výjimkou je funkce fopen. V příkladu jsme si ukázali otevření /etc/passwd pro čtení příkazem

fopen("/etc/passwd", "r");

V případě zápisu do textového souboru použijeme jako druhý parametr "w" nebo "a". Pokud soubor neexistuje, v obou případech je vytvořen nový. Rozdíl nastane u existujícího souboru. Otevření pomocí "w" smaže původní obsah souboru (například textový editor ukládá soubor), zatímco "a" znamená zápis na konec souboru (například přidání nového uživatele do /etc/passwd). Funkce fopen nemusí vždy uspět, nejčastější příčinou je nedostatečné oprávnění uživatele k danému souboru nebo adresáři.

Pro zápis můžeme použít uvedené analogie funkcí puts, putchar a printf. Hlavním rozdílem je, že fputs sama od sebe neodřádkuje, jinak se všechny tři funkce chovají podobně jako jejich protějšky pro standardní výstup.

int fputs(const char *s, FILE *stream);
int fputc(int c, FILE *stream);
int fprintf(FILE *stream, const char *format, ...);

Podobné je to i u čtení, i zde máme analogie funkcí gets, getchar a scanf. Funkce gets má navíc parametr size, který omezí maximální délku přečtené řádky (narozdíl od gets, která v případě nekonečné řádky čte tak dlouho, až program spadne na přetečení bufferu a nelze tomu nijak zabránit), a pokud narazí na konec řádky, uloží do bufferu i znak '\n', zatímco gets jej zahodí.

int fgets(char *s, int size, FILE *stream);
int fgetc(FILE *stream);
int fscanf(FILE *stream, const char *format, ...);

Po skončení čtení nebo zápisu soubor uzavřeme funkcí fclose.

int fclose(FILE *stream);

Binární režim

Pro práci se souborem, chápaným jako pole bytů, použijeme binární režim. Následující příklad zhruba odpovídá příkazu

cp /etc/passwd /home/honza/passwd

Všimněte si, že použijeme binární mód pro kopírování souboru obsahující textová data.

#include <stdio.h>

int main(void) {
  FILE *fr, *fw;
  unsigned char buf[1024];
  size_t precteno, zapsano;
  
  fr = fopen("/etc/passwd", "rb");
  if (!fr) {
    fputs("Nemohu otevřít vstupní soubor.\n", stderr);
    return 1;
  }
  fw = fopen("/home/honza/passwd", "wb");
  if (!fw) {
    fclose(fr); 
    fputs("Nemohu otevřít výstupní soubor.\n", stderr);
    return 2;
  }
  
  while (precteno = fread(buf, 1, sizeof(buf), fr)) {
    zapsano = fwrite(buf, 1, precteno, fw);
    if (precteno > zapsano) {
      fputs("Chyba zápisu do souboru.\n", stderr);
      break;
    }
  }
  if (ferror(fr)) {
    fputs("Chyba čtení ze souboru.\n", stderr);
  }
  fclose(fr);
  fclose(fw);
  return 0;
}

Nejprve jsme oba soubory otevřeli funkcí fopen. Písmeno 'b' v parametru určujícím režim práce se souborem, znamená binární mód. Vlastní kopírování probíhá ve while cyklu, který může skončit chybou čtení nebo zápisu a nebo koncem souboru /etc/passwd. Funkce fread čte ze souboru fr do bufferu buf sizeof(buf) bloků dat velikosti 1 byte. Návratovou hodnotou je počet přečtených bloků, který je v našem případě shodou okolností rovný počtu přečtených bytů. Pokud funkce narazí na konec souboru nebo dojde v průběhu čtení k chybě, vrátí funkce menší počet bloků, případně nulu. Zápis do /home/honza/passwd probíhá zcela analogicky funkcí fwrite. Zde je menší než požadovaný počet zapsaných bloků dat vždy chybou. Po ukončení kopírovacího cyklu je dobré se ještě ujistit, že cyklus neskončil kvůli chybě čtení ze souboru pomocí ferror, neboť z návratové hodnoty fread nepoznáme, zda jsme jen narazili na konec souboru nebo došlo k nějaké (například diskové) chybě.

Nyní si ukážeme nejdůležitější funkce pro binární režim.

FILE *fopen(const char *path, const char *mode);

Použití funkce fopen se od textového režimu liší především přidáním 'b' do řetězce mode, navíc má rozumný smysl otevřít soubor pro čtení i zápis zároveň.

modesoubor existovalsoubor neexistoval
rbotevře pro čteníchyba
rb+otevře pro čtení a zápischyba
wbsmaže obsah a otevře pro zápisvytvoří a otevře pro zápis
wb+smaže obsah a otevře pro čtení a zápisvytvoří a otevře pro čtení a zápis
abotevře pro zápis na konec souboruvytvoří a otevře pro zápis
ab+otevře pro čtení a zápis na konec souboruvytvoří a otevře pro čtení a zápis

V otevřeném souboru je jakýsi neviditelný ukazatel na aktuální pozici, čtení a zápis jej posunou o velikost přenášených dat. Tento ukazatel můžeme také posouvat explicitně, proto může mít smysl otevírat soubor například v režimu "ab+", ačkoli čtení z konce souboru smysl nemá.

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

Funkce fread a fwrite jsme si dostatečně vysvětlili již v příkladu, pouze uvedu, že velikost přenášených dat je size * nmemb. Řada programátorů to považuje za zbytečné zadávání jednoho čísla pomocí dvou parametrů a jako parametr size předávají vždy 1.

int fclose(FILE *stream);

Použití funkce fclose se od textového režimu nijak neliší.

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);

Funkcí fseek posouváme aktuální pozici v souboru a pomocí ftell ji můžeme zjistit. Parametr whence nabývá hodnot SEEK_SET, SEEK_CUR a SEEK_END podle toho, zda offset znamená posunutí od začátku, aktuální pozice nebo konce souboru, offset tedy může být i záporné číslo.

int ferror(FILE *stream);
int feof(FILE *stream);

Pomocí funkcí ferror a feof zjistíme, zda je aktuální pozice na konci souboru respektive zda došlo k chybě. Tyto funkce se používají i v textovém režimu.

int remove(const char *pathname);

Trochu stranou od ostatních uvedených funkcí je remove, která smaže soubor nebo prázdný adresář.

Všimněte si, že řadu užitečných funkcí standardní C knihovna nenabízí. Jedná se zejména o práci s adresáři nebo atributy souboru. V tomto případě obvykle programátor použije systémová volání charakteristická pro konkrétní typ operačního systémy, multiplatformní programy nad nějakou všeobjímající knihovnou typu Qt nebo WXwidgets pak volají funkce této knihovny.

Pokračování příště

V příštím dílu si ukážeme implementaci vlastních funkcí s proměnným počtem parametrů.

Verze pro tisk

pridej.cz

 

DISKUZE

svele, jen tak dal 15.9.2005 11:15 P.B.




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

15.4.2017 15:20 /František Kučera

Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě IoT a radiokomunikace? Přijď na sraz spolku OpenAlt, který se bude konat ve středu 19. dubna od 18:30 v Šenkovně (Sokolská 60, Praha 2).


Přidat komentář

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

27.2.2017 22:12 /František Kučera
Pozvánka na 137. sraz OpenAlt – Praha: Tentokrát jsme si pro vás připravili neobvyklou akci. Ve středu 1.3. v 17:30 nás přivítá sdružení CZ.NIC ve svých prostorách v Milešovské ulici číslo 5 na Praze 3, kde si pro nás připravili krátkou prezentaci jejich činnosti. Následně navštívíme jejich datacentrum pod Žižkovskou věží. Provedou nás prostory, které jsou běžnému smrtelníkovi nedostupné!
Po ukončení prohlídky se všchni odebereme do hostince U vodoucha, Jagelonská 21, Praha 3 pochutnat si na některém z vybraných piv či dát si něco na zub. Rezervaci máme od 19:30, heslo je OpenAlt.
Ale pozor! Do prostor datového centra máme omezený přístup, dostane se tam pouze 10 lidí! Takže kdo přijde dříve, ten má přednost, a občanky s sebou! Kdo nebude chtít na prohlídku datového centra, může se pomalu přesunout do hostince U vodoucha a u nepřeberné nabídky piv počkat na ostatní.
Přidat komentář

18.1.2017 0:49 /František Kučera
Členové a příznivci spolku OpenAlt se pravidelně schází v Praze a Brně. Fotky z pražských srazů za uplynulý rok si můžete prohlédnout na stránkách spolku. Příští sraz se koná už 19. ledna – tentokrát je tématem ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. Také budete mít příležitost si prohlédnout pražský hackerspace Brmlab.
Přidat komentář

8.1.2017 17:51 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 19. ledna od 18:30 v pražském hackerspacu Brmlab. Tentokrát je tématem srazu ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. K vidění bude mechanická klávesnice dasKeyboard, trackball Logitech nebo grafický tablet (a velký touchpad) Wacom. Přineste i vy ukázat svoje zajímavé klávesnice a další HW. V 18:20 je sraz před budovou, v 18:30 jdeme společně dovnitř, je tedy dobré přijít včas. Podle zájmu se později přesuneme do nějaké restaurace v okolí.
Přidat komentář

1.12.2016 22:13 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 8. prosince od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Sraz bude tentokrát tématický. Bude retro! K vidění budou přístroje jako Psion 5mx nebo Palm Z22. Ze svobodného hardwaru pak Openmoko nebo čtečka WikiReader. Přijďte se i vy pochlubit svými legendami, nebo alespoň na pivo. Moderní hardware má vstup samozřejmě také povolen.
Komentářů: 1

4.9.2016 20:13 /Pavel `Goldenfish' Kysilka
PR: Dne 22.9.2016 proběhne v Praze konference Cloud computing v praxi. Tématy bude např. nejnovější trendy v oblasti cloudu a cloudových řešení, provozování ERP v cloudu, o hostování různých typů softwaru, ale třeba i o zálohování dat nabízeném podnikům formou služby.
Přidat komentář

1.9.2016 11:27 /Honza Javorek
Česká konference o Pythonu, PyCon CZ, stále hledá přednášející skrz dobrovolné přihlášky. Máte-li zajímavé téma, neváhejte a zkuste jej přihlásit, uzávěrka je již 12. září. Konference letos přijímá i přednášky v češtině a nabízí pomoc s přípravou začínajícím speakerům. Řečníci mají navíc vstup zadarmo! Více na webu.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

17.4.2017 19:15 / Jakub shoop
chyba

7.4.2017 15:43 / Som
foreign car repair

31.3.2017 18:33 / David Ostrovsky
Dotazník na obeznámenost s hummusem.

24.3.2017 11:54 / Hui
country cottages

16.3.2017 16:33 / BezvaDesign.cz
Re: Hledám grafika do teamu

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2017) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze