na obsah klávesové zkratky na hlavní stránku na menu

Soubory

Soubory patří k základním datovým prvkům v počítači. Převážná většina programovacích jazyků má podporu určité formy práce se soubory. V jazyce C k tomuto účelu slouží funkce fopen(), fclose(), fscanf(), fprintf(), getc(), putc() a další.

Otevření souboru

Se soubory se v každém systému pracuje trochu jinak. Například v systému Windows jsou cesty oddělovány zpětnými lomítky a disk se značí velkým písmenem. V systémech odvozených od UNIXu se adresáře oddělují obyčejnými lomítky a pojmenování diskových oddílů písmeny neexistuje. Každý systém má také jinou filozofii oprávnění. Standard jazyka C poskytuje jistou formu abstrakce v podobě funkce fopen() z hlavičkového souboru stdio.h, která otevře soubor pro manipulaci. Funkce má následující synatxi:

FILE *fopen(const char *cesta, const char *způsob);

Funkce přejímá dva parametry, oba jsou řetězce. První řetězec je cesta k souboru, ke kterému si přejeme přistoupit. Formát cesty je závislý na cílové platformě. způsob je kód operace, kterou si přejeme se souborem provést. Dostupné způsoby práce jsou:

"r"
Otevře soubor pro čtení. Zápis do souboru skončí chybou. Soubor musí existovat.
"w"
Vytvoří prázdný soubor pro zápis. Pokud soubor existuje, bude jeho obsah nejprve vymazán.
"a"
Otevře soubor pro zápis na konec. Soubor je vytvořen, pokud neexistuje. Veškeré zápisy probíhají na konci existujícího obsahu.
"r+"
Otevře soubor pro čtení i zápis. Soubor musí existovat.
"w+"
Vytvoří prázdný soubor pro čtení i zápis. Pokud soubor existuje, bude jeho obsah nejprve vymazán.
"a+"
Otevře soubor pro čtení kdekoliv a zápis na konec. Soubor je vytvořen, pokud neexistuje. Veškeré zápisy probíhají na konci existujícího obsahu, i když předtím čteme na jiném místě souboru.

Kromě výše uvedených způsobů manipulace existuje ještě varianta s písmenem b, které lze umístit na konec řetězce nebo před znak +. Takový soubor bude chápán jako binární soubor, kdežto výše uvedené způsoby otevírají soubor jako textový. Na systémech odvozených od UNIXu není ve způsobu zacházení s textovými a binárními soubory žádný rozdíl, přesto se písmeno b doporučuje přidat kvůli přenositelnosti.

Funkce vrací ukazatel na strukturu FILE. Pokud dojde k chybě, vrátí funkce NULL, jinak obdržíme ukazatel na strukturu, v níž jsou uchované některé důležité údaje nutné pro práci se souborem. Tyto informace jsou ovšem před programátorem skryty, neboť se mohou systém od systému lišit.

FILE *f, *g;
// otevření konfiguračního souboru pro čtení v linuxovém systému
f = fopen("/etc/X11/xorg.conf", "r");
/* otevření konfiguračního souboru pro čtení v systému Windows
je nutné psát dvě zpětná lomítka, jinak bude následující znak chápán
jako řídící sekvence
*/
g = fopen("C:\\boot.ini", "r");

Ostatní funkce pro práci se souborem

Abychom mohli pracovat se souborem, je nejprve nutné ho otevřít pomocí výše uvedené funkce fopen() a získat ukazatel na strukturu FILE. Poté se se souborem pracuje podobně jako se standardním vstupem a výstupem (což není náhoda). Následuje seznam několika důležitých funkcí pro manipulaci se souborem:

int fclose(FILE *f)
Bezpečně uzavře předem otevřený soubor. Každý otevřený soubor by měl být řádně ukončen. Funkce vrací EOF (End Of File), nastane-li chyba.
int fscanf(FILE *f, const char *maska, ...)
Tato funkce funguje naprosto stejně jako funkce scanf() s tím rozdílem, že zdrojem dat je otevřený soubor f.
int fprintf(FILE *f, const char *maska, ...)
Tato funkce funguje naprosto stejně jako funkce printf() s tím rozdílem, že cílem je otevřený soubor f.
int fgetc(FILE *f);
Funkce přečte ze souboru právě jeden znak a přesune se na další. Pokud nastane chyba, vrátí funkce EOF.
int fputc(int c, FILE *f);
Funkce vypíše právě jeden znak do souboru. Pokud nastane chyba, vrátí funkce EOF.
long ftell(FILE *f);
Vrátí aktuální pozici v souboru v bajtech.
int fseek(FILE *f, long posun, int start);
Přesune se na pozici v souboru. Cíl je určen relativním posunem o posun bajtů vůči startovní pozici start. Startovní pozice může být SEEK_SET (začátek souboru), SEEK_CUR (aktuální pozice), SEEK_END (konec souboru). Funkce vrací mínus jedna, pokud nastane chyba.
int fflush(FILE *f);
Vyprázdní vyrovnávací paměť a zapíše veškerý dosud nezapsaný obsah do souboru. Tato funkce by se měla volat mezi po sobě jdoucím čtením a zápisem nebo zápisem a čtením do souboru. Pokud nastane chyba, vrátí funkce EOF.
FILE *tmpfile(void);
Vytvoří soubor s unikátním jménem tak, aby nedošlo ke jmenné kolizi. Soubor bude automaticky smazán po uzavření.

Jednoduchý program, který vypíše obsah předaného souboru, bude tedy vypadat takto:

#include <stdio.h>

int main (int argc, char **argv)
{
  // byl předán název souboru?
  if (argc < 2) return -1;
  // otevřeme soubor, relativní cesta se vyhodnocuje k pozici
  // spuštěného programu
  FILE *f = fopen(argv[1], "r");
  // povedlo se otevřít?
  if (f == NULL) return -1;
  int c;
  // přečti obsah znak po znaku a vypiš
  while ((c = fgetc(f)) != EOF)
  {
    putc(c);
  }
  // uzavřeme soubor
  fclose(f);
  return 0;
}

Všimněme si nyní, že se pro manipulaci se znakem používá typ int a nikoliv char, jak bychom očekávali. Je to z toho důvodu, že funkce fgetc() signalizuje chybu pomocí zvláštní návratové hodnoty EOF (End Of File). Kdyby funkce vracela znaky, nezbyl by pro tuto konstantu žádný kód. Proto je nutné rozšířit návratový typ na int, kde už EOF existovat může.

Standardní vstup a výstup jako soubory

Ač se to může zdát zvláštní, standardní vstup a standardní výstup nejsou nic jiného než soubory a jazyk C s nimi ani jinak nepracuje. Standard pouze poskytuje funkce, které práci s nimi usnadňují, můžeme s nimi ale pracovat pomocí souborových funkcí. Před spuštěním našeho kódu dojde k automatickému otevření tří souborů – stdin, stdout a stderr. Tyto soubory jsou na konci programu automaticky uzavřeny. Soubor stdin je otevřen pro čtení a obsahuje vstup programu, soubor stdout je otevřen pro zápis a obsahuje výstup programu. Konečně soubor stderr je soubor otevřený pro zápis a obsahuje chybová hlášení programu. Výstup a výpis chyb tak lze oddělit. Pokud chceme vypsat hlášení na standardní chybový výstup, můžeme použít funkci fprintf() s prvním parametrem stderr.