Práce se soubory (a stdio.h)
V této kapitole začnu systematický výklad funkcí z knihovny <stdio.h>. Její název je odvozen ze slov standard input output, neboli standardní vstup a výstup. V předchozí kapitole jste se mohli podívat na přehled funkcí deklarovaných v souboru <stdio.h>. V této kapitole vysvětlím něco málo nezbytné teorie a v dalších kapitolách se podíváme na praxi. Doposud jste používali pouze vstup z klávesnice a výstup na monitor, ale už nastal čas naučit se pracovat se soubory :-).
O vstupu a výstupu
O vstupu a výstupu jsem povídal v souvislosti s funkcemi
printf() a scanf().
Bylo by možná dobré, kdybyste si oprášili pojmy jako stdin,
stdout a stderr, nebo výrazy
bloková a znaková
zařízení. Funkce printf()
a
scanf()
jsou typickými představiteli
knihovny <stdio.h>. Spoustu z toho, co ste se v souvislosti s těmito
funkcemi dozvěděli (např. o formátovacích řetězcích) využijete i v
dalších funkcích. Nakonec si ještě dovolím připomenout makro
EOF (End Of File), které se používá k indikaci konce
souboru.
Standardní vstup a výstup se považují také za soubory (s drobnými rozdíly, například „skutečné“ soubory mají své jméno a jsou někde uloženy …). Na rozdíl od ostatních souborů (např. textových, binárních a dalších speciálních souborů) jsou standardní vstup a výstupy otevřeny a programu přístupny automaticky při spuštění programu. Jak zajistit přístup k ostatním souborům, nebo jaký je rozdíl mezi textovými a binárními soubory se dozvíte při výkladu funkcí, které s těmito soubory pracují. Jelikož však už víte, co jsou to struktury, můžu vám ukázat deklarace standardního vstupu a výstupu:
FILE *stdin; | Standardní vstup (typicky klávesnice) |
---|---|
FILE *stdout; | Standardní výstup (typicky obrazovka) |
FILE *stderr; | Standardní chybový výstup (typicky obrazovka) |
Jedná se o ukazatele na strukturu FILE
. Ta je
deklarovaná v souboru <stdio.h> a slouží k práci se soubory.
Jak tato struktura vypadá není důležité. Zmiňuji se o ní v této
chvíli proto, protože struktura FILE je argumentem
spousty funkcí ze souboru <stdio.h>.
Přístup k souborům
Existují dva základní způsoby jazyka C, jak přistupovat k souborům. Buďto pomocí souborového proudu, nebo pomocí přímého volání.
Souborový proud
Knihovna <stdio.h> deklaruje přístup pomocí souborového proudu. Tento způsob přístupu k souborům je definován normou ANSI jazyka C (a také normou POSIX). K souborovému proudu se přistupuje pomocí struktury FILE. Díky normě ANSI máte jistotu, že používané funkce budou podporovány všemi („dobrými“) překladači. Díky tomu je převážně používán tento způsob práce se soubory. Tímto způsobem přístupu k souborům se budu zabývat nejdříve.
Souborové proudy mají obvykle vyrovnávací paměť (buffer). To znamená, že se při otevření načte z disku několik (stovek) bajtů do bufferu. Když se pak pokusíte něco přečíst, čtete rovnou z bufferu, což je rychlé. Když se dostanete na konec bufferu, načte se další (velký) kus z disku do pěmati (bufferu).
Při zápisu pracují buffery také. Zapisovaná data se nezapisují znak po znaku, ale nejdříve
se nashromáždí v bufferu. Když jse buffer plný, pak se všechno zapíše na disk naráz (což
je rychlejší). Vzpomeňte na funkci fflush()
.
Přímé volání
Přímé volání má přímou vazbu na systém. Tím je zaručena maximální
rychlost přístupu k souborům, ale také implementační závislost. Pro
funkce pracující s přímím voláním je potřeba použít knihovny
<io.h>, <sys/stat.h> a <fcntl.h>. K souboru se
nepřistupuje pomocí struktury FILE
, ale pomocí manipulačního čísla
tzv. deskriptoru souboru. Jedná se o datový typ int. Přímé
volání není součástí normy ASCII, ale je definována normou POSIX.
Přímé volání se obvykle nepoužívá pro práci s běžnými soubory, ale například s deskriptory, které zprostředkovávají čtení dat po síti atp. Díky takovýmto deskriptorům můžete číst data z internetu (nebo z jiných „nesouborých“ zrdrojů). Dokonce existuje způsob, jak převést deskriptor souboru na souborový proud. O tom všem bude ještě řeč (částečně v programování pod Linuxem).
Textový a binární přístup k souborům
Existuje ještě jedno dělení přístupu k souborům a to na textový a binární přístup. Textový soubor je takový soubor, ve kterém je uložen pouze text. Toto překvapivé zjištění umožňuje zjednodušit některé souborové operace a zlepšit tak přenositelnost mezi různými operačními systémy.
Problém textových souborů spočívá, kromě kódování,
ve znaku '\n'
. Je to
označení konce řádku ("Enter"). V DOSu/Windows je konec řádku dán dvěma bajty 13 a
10, zatímco v Linuxu pouze jedním (10). V jiných systémech je
to pro změnu jen 13 (Apple). Při textovém přístupu k
souboru můžete načítat a zapisovat textové řetězce. Přitom se
nemusíte starat o to, jakým způsobem je znak '\n'
interpretován. Nový řádek je vnitřně reprezentován
jedním znakem, který je vždy roven '\n'
(při čtení/zápisu souboru dochází k automatické konverzi).
13 (CR) odpovídá znaku „návrat vozíku“ (carridge return). To byl signál pro tiskárnu,
že se má vrátit na začátek řádku papíru (doleva). 10 (LF) byl zase signál posunutí
o řádek dále. Sekvence '\n' označuje LF, sekvence '\r' označuje CR.
Ale jak jsem psal, při výstupu funkce printf()
a podobných se automaticky změní '\n' na takovou hodnotu (hodnoty),
která je pro daný operační systém běžná.
Při binárním přístupu k souboru čtete i zapisujete
data bajt po bajtu. V takovém případě, pokud chcete zapsat textový
soubor, musíte zapsat znak '\n'
v závislosti na tom, v jakém OS jej budete chtít číst. Při binárním
přístupu máte tedy větší
kontrolu nad zpracovávanými daty, ale práce s takovými soubory může
být o něco náročnější.
Limity
V souboru <stdio.h> najdete makra FOPEN_MAX a FILENAME_MAX.
FOPEN_MAX udává podprou pro minimální počet otevřených souborových proudů (např. 16). Maximum
otevřených souborů omezuje operační systém, mnohdy podle aktuální
konfigurace systému. Pokud se pokusíte otevřít více souborů, otevření souboru
selže.
FOPEN_MAX se týká limitu otevřených souborových proudů (v jeden okamžik), netýká
se přímého volání.
FILENAME_MAX udává maximální délku jména souboru (např. 512 nebo 4096). V systému MS-DOS je známé omezení 8+3, tj. 8 znaků na jméno, tečka a tři znaky (přípona). Nicméně, FILENAME_MAX se vztahuje na délku absolutního jména souboru, tj. jména se jmény všech předcházejících adresářů.
Chcete-li, aby vaše programy byli maximálně přenositelné, využívejte těchto maker.