12. cvičení
Práce se soubory
Pro práci se soubory v jazyce C slouží struktura FILE
a několik funkcí
definovaných v hlavičkovém souboru stdio.h
:
fopen
otevře souborfflush
zapíše obsah souboru na disk a soubor nechá otevřenýfclose
zapíše obsah souboru na disk a zavře soubor
Při otevírání souboru je potřeba specifikovat, jestli chceme daný soubor otevřít pouze pro čtení, nebo pouze pro zápis. (Kombinace čtení a zápisu ve stejném souboru je sice možná, ale komplikovaná, takže se jí nebudeme zabývat.) Soubor pro zápis můžeme otevřít např. takto:
FILE* soubor = fopen("text.txt", "w");
if (soubor == NULL) {
printf("chyba otevreni souboru\n");
return 1;
}
Soubor pro čtení se otevře stejně, ale místo řetězce "w"
se použije "r"
.
Po skončení práce s daným souborem je potřeba zavolat funkci fclose
pro
zavření souboru:
fclose(soubor);
Pokud bychom na zavření souboru zapomněli, nedošlo by k uvolnění alokované paměti a složitější programy by kvůli tomu mohly skončit chybou, protože každý operační systém má nějaký limit na počet otevřených souborů.
Zápis do souboru
Pro zápis dat do souboru je nejjednodušší použít funkci fprintf, která funguje v podstatě stejně jako funkce printf, pouze první parametr je ukazatel na soubor, kam se má text zapsat:
fprintf(soubor, "Hello, world!\n");
Pro zápis jediného znaku je možné použít funkci fputc (analogie k funkci putchar):
fputc(znak, soubor);
Čtení ze souboru
Pro čtení dat ze souboru existuje funkce fscanf, která funguje v podstatě stejně jako funkce scanf, pouze první parametr je ukazatel na soubor, ze kterého se má číst:
fscanf(soubor, "%d", &cislo);
Pro čtení textu však platí stejná poznámka, jako pro funkci scanf. Proto je lepší text ze
souborů načítat ručně znak po znaku, k čemuž slouží funkce fgetc (analogie k funkci getchar). Funkci getLine
z minulého
cvičení můžeme upravit pro čtení ze souboru takto:
// funkce pro nacteni jednoho radku textu ze souboru
bool fgetLine(FILE* soubor, char* string, int maxDelka)
{
for (int i = 0; i < maxDelka; i++) {
// precti znak z terminalu
int znak = fgetc(soubor);
// kontrola jestli nedoslo k chybe cteni
if (ferror(soubor)) {
printf("Chyba: neslo precist cely radek\n");
return false;
}
// zkontroluj, jestli neni konec vstupu
if (znak != EOF && znak != '\n')
string[i] = znak;
else {
// konec vstupu - ukonci string a prerus cyklus
string[i] = '\0';
return true;
}
}
// v cyklu jsme nedosli ke znaku EOF ani k '\n' - radek je delsi nez (maxDelka - 1)
// (vypisujeme maxDelka - 1, protoze posledni znak musi byt '\0', ktery ale uzivatel nezadava)
printf("Chyba: radek je delsi nez maximalni povolena delka %d znaku.\n", maxDelka - 1);
return false;
}
Oproti funkci getLine
zde navíc pomocí funkce ferror kontrolujeme, jestli nedošlo k chybě
čtení. Také existuje funkce feof,
která kontroluje, jestli jsme došli na konec souboru (hodí se hlavně v kombinaci
s funkcí fscanf
).
Důležité poznámky
-
Při práci se soubory se používá konstanta
EOF
(zkráceně end of file), která znamená, že jsme narazili na konec souboru a nemůžeme číst další znaky. To může nastat dvěma způsoby: buď jsme opravdu došli až na konec souboru a další znaky prostě neexistují, nebo při čtení došlo k nějaké chybě (např. porucha disku, chyba operačního systému apod.). Proto je potřeba rozlišovat kontrolu pomocí funkcíferror
afeof
(viz předchozí odstavec). -
Existují globální proměnné
stdin
astdout
, které reprezentují standardní vstup a standardní výstup programu. V běžných případech jsou standardní vstup a standardní výstup připojeny k terminálu, ve kterém spouštíme program. S proměnnýmistdin
astdout
lze pracovat stejně jako se soubory otevřenými pro čtení, resp. pro zápis. Funkce jakoprintf
,scanf
neboputchar
používají tyto proměnné implicitně. -
Nové funkce pro práci se soubory, které jsme použili na dnešním cvičení:
fprintf
,fscanf
,fgetc
,fputc
,putchar
,getchar
,ferror
,feof
. Všechny jsou dostupné v hlavičkovém souborustdio.h
, viz úplný přehled.
Probrané příklady
- Program demonstrující základní práci se soubory (viz jednotlivé příkazy výše).
- Různé způsoby načítání textu ze souboru:
- znak po znaku (cyklus s funkcí
fgetc
) - řádek po řádku (cyklus s funkcí
fgetc
a ukončení znakem'\n'
, viz funkcefgetLine
výše) - slovo po slovu (cyklus s funkcí
fgetc
, přeskočení všech prázdných znaků na začátku a ukončení libovolným prázdným znakem)
- znak po znaku (cyklus s funkcí
- Program pro určení délky nejdelšího slova a počtu slov v textovém souboru (modifikace programu z předchozího cvičení).
- Program, který přečte text ze souboru a slovo z terminálu, vyhledá zadané slovo v textu, přepíše všechny výskyty tohoto slova v textu velkými písmeny a výsledný řetězec zapíše do jiného souboru.