Hledejte v chronologicky řazené databázi studijních materiálů (starší / novější příspěvky).

24. Operace s ostatními soubory, ovládání souborů prostřednictvím ukazatelů.

Práce se soubory:
V jazyce C++ je práce se soubory realizována pomocí tzv. datových proudů (streams), které si lze představit jako určitou konečnou posloupnost bytů, jako jsou například soubory. Datové proudy ale nemusí nutně představovat jenom soubory, ale mohou to být třeba data proudící sítí apod. Datovými proudy jsou například i standardní vstup a výstup.

Souborový proud je v C++ představován ukazatelem na strukturu FILE(možno použít jako příklad předchozí otázky ukazatel na struktury☺), ve které jsou uloženy nejrůznější informace o příslušném souboru, a tak můžeme tento proud definovat stejně jako jakýkoliv jiný ukazatel v C.

FILE *identifikátor;

Takto nadefinovaný pointer je ale samozřejmě neinicializovaný a pro přístup k souboru jej tedy ještě nelze použít. Pro jeho inicializaci použijeme funkci fopen().


Otevření souboru

FILE *fopen(char *jméno_souboru, char *mód_otevření);

Funkce fopen() se pokusí otevřít soubor, jehož jméno jsme jí předali v řetězci jméno_souboru. V případě, že se soubor podařilo otevřít, vrátí funkce příslušný ukazatel. Pokud se však soubor otevřít nepodařilo (například pokud nebyl nalezen), vrací hodnotu NULL. Protože možnost, že se soubor nepodaří otevřít, je velice reálná, neměli bychom zapomínat tuto skutečnost testovat.
Druhým parametrem mód_otevření určujeme, v jakém módu bude soubor otevřen. I tento parametr je definován jako řetězec. Jednotlivé režimy otevření souboru určujeme pomocí kombinace několika znaků.

r (read) Soubor bude otevřen pro čtení.

w (write) Soubor bude otevřen pro zápis. V případě, že otevíraný soubor již existuje, bude nejdřív zkrácen na nulovou délku. Pokud otevíraný soubor dosud neexistuje, vytvoří se nový.

a (append) Stejně jako v předchozím případě bude soubor otevřen pro zápis. Pokud otevíraný soubor neexistuje, vytvoří se nový, ale jestliže soubor již existuje, nebude, narozdíl od módu w, nijak zkracován.

Po otevření souboru se automaticky nastavuje pozice tzv. file-pointeru, tedy místa, ze kterého se bude číst, nebo kam se bude zapisovat. Pro módy r a w je file-pointer nastaven na začátek souboru a pro soubor otevřený v režimu append je nastaven na pozici za posledním bytem souboru. Mód append je tedy určen pro připojení nových dat k souboru.

Všechny tři režimy otevření souboru lze ještě doplnit o znaménko +. Pak bude soubor otevřen najednou pro čtení i zápis.

Dále můžeme v C++ otevírat soubory buď jako textové, nebo jako binární(zvlášť vhodné pro struktury). To určíme pomocí znaků b nebo t připojených k řetězci mode. Oba způsoby jsou skoro stejné, ale narozdíl od souborů, které byly otevřeny jako binární, pro soubory otevřené v textovém módu se při čtení i při zápisu provádí konverze oddělovače řádků. Je- li tedy, například v DOSu, oddělovačem řádků sekvence znaků '\13' a '\10', ze souboru se celá dvojice přečte jako znak '\n'. Naopak, pokud zapisujeme znak '\n', ve skutečnosti se zapíše celá kombinace '\13' a '\10'.

Příklad: Testování, zda byl soubor otevřen

FILE *f;

...

f = fopen("soubor.txt", "rb+");
if (f==NULL) { puts("Chyba: Soubor se nepodařilo otevřít.");
return(false);
}
...

Uzavření souboru
Přestaneme-li s otevřeným souborem pracovat, měli bychom ho, ačkoliv to není povinné, hned uzavřít. Počet najednou otevřených souborů je totiž omezen. Uzavření souboru provedeme voláním funkce fclose().

int fclose (FILE *file);

Podařilo-li se soubor uzavřít, vrací funkce hodnotu 0. Opačný případ, tedy že se soubor uzavřít nepodařilo, nastává nejčastěji, snažíme-li se uzavřít v dané chvíli neotevřený soubor. V takovém případě vrací funkce hodnotu EOF. Jiný důvod selhání prakticky nenastává, a proto se návratová hodnota funkce fclose() většinou ani netestuje.

Testování konce souboru
Testovat konec souboru se dá v zásadě dvěma způsoby. Buď kontrolou návratových hodnot čtecích funkcí, nebo použitím funkce feof(). První způsob se používá především pro čtení pomocí funkce getc(), která vrací hodnotu EOF, pokud bylo dosaženo konce souboru. Druhým způsobem, pomocí funkce feof(), můžeme stejnou skutečnost zjistit pro libovolnou operaci čtení. Pokud se poslední taková operace pokoušela číst již za koncem souboru, vrací funkce feof() pravdivou (nenulovou) hodnotu. V opačném případě vrací nulu.

int feof(FILE *file);

Funkce pro zápis do souboru
Pro zápis do souboru nám poslouží funkce putc(), fprintf(), a fputs(), jejichž deklarace jsou zde:

int putc(int c, FILE *file);
int fprintf(FILE *file, char *formát, ...);
int fputs (char *string, FILE *file);

Po provedení některé z těchto funkcí se file-pointer posune v souboru za poslední zapsaný byte. To ostatně platí i pro všechny další funkce zapisující do souboru.

Funkce fwrite() – slouží pro binární zápis

int fwrite(void *ptr, int size, int n, FILE *file);

Funkce fwrite() zapíše do proudu file n položek přečtených z paměti označené ukazatelem ptr. Velikost jedné položky v bytech udává parametr size, takže celkový počet zapisovaných bytů je roven size*n. Funkce fwrite() vrací počet úspěšně zapsaných položek, nikoli bytů!

Funkce pro čtení ze souboru

int getc(FILE *file);
int fscanf(FILE *file, char *formát, ...);
char *fgets(char *string, int n, FILE *file);

Zajímavá je především funkce fgets, která oproti příbuzné funkci gets umožňuje definovat maximální počet přečtených znaků a lze ji použít i ke čtení ze standardního vstupu.

char str[50];

fgets(str, 49, stdin);

I funkce čtoucí ze souboru posouvají file-pointer, a to za poslední přečtený znak souboru.

Funkce fread() – slouží pro binární čtení
Pro blokové čtení ze souboru nám poslouží funkce fread():

int fread(void *ptr, int size, int n, FILE *file);

Z datového proudu file přečte n položek o velikosti size bytů a uloží je do paměti označené ukazatelem ptr. Návratovou hodnotou je počet skutečně přečtených položek.

Nesekvenční přístup:
Na souborové datové proudy lze použít tzv. nesekvenční (náhodný) přístup, což znamená, že nemusíme číst jeden byte za druhým tak, jak jsou v souboru uloženy, ale můžeme „skákat“ (přesunovat file-pointer) na libovolnou pozici v souboru. K tomuto účelu slouží funkce fseek().
int fseek (FILE *file, long offset, int mode);

Funkce přesune file-pointer na pozici vzdálenou offset bytů od pozice mode, přičemž za parametr mode je možné zvolit jednu z následujících konstant:

SEEK_SET Začátek souboru
SEEK_CUR Aktuální pozice v souboru
SEEK_END Konec souboru

Příklady:

zápis file----------------pointer se přesune na...
fseek(f, 0, SEEK_SET); začátek souboru
fseek(f, 0, SEEK_END); konec souboru
fseek(f, -10, SEEK_CUR); pozici o deset bytů zpět od aktualní pozice
fseek(f, 10, SEEK_SET); jedenactý byte souboru

Je-li soubor, se kterým pracujeme, otevřen v módu pro čtení i zápis, musíme mezi každou operací čtení a operací zápisu volat funkci fseek(). Tato nepříjemnost je nutná kvůli synchronizaci file-pointerů, které jinak nemusí být správně nastaveny. Funkci fseek() ale můžeme volat i s nulovým posunem.

Chceme-li zjistit, jaká je aktuální pozice file-pointeru v souboru, můžeme použít funkci ftell(), která tuto pozici vrací jako svou návratovou hodnotu.

long ftell (FILE *file);

Žádné komentáře:

Okomentovat