Fájlkezelés, adattárolás



1.1     File kezelés

A C nyelvben aza datállományokat tartalmuk alapján két csoportra oszthatjuk, szöveges és bináris állományokra. A szöveges állományok olvasható információt tartalmaznak. Sorokból épülnek fel, minden sor végét a CR/LF karakterpár zárja.A bináris állományok byte-okból felépülő adtahalmazt jelentenek. A szöveges állomány minden esetben földolgozható, mint bináris állomány, de ez fordítva már nem igaz.

Szöveges állományokban is lehet számokat tárolni. Ebben az esetben a számok, mint karakterek fogan tárolódni. Ha például egy négy jegyű számot szöveges állományban tárolunk, akkor négy byte-nyi helyet foglal el, ha azonban egy bináris állományba tesszük le, akkor csak 2 byte kell. (Természetesen csak akkor, ha int típusú volt)

1.1.1    File előkészítése, lezárása

A file kezeléshez tartozó függvények az stdio.h deklarációs állományban vannak leírva. Minden file-hoz hozzá kell rendelni egy FILE típusú muatatót, mely a memóriában a file jellemzőire mutat[1]. Ennek formája:

FILE *fp;

Ez után következhet a file megnyitása:

fp=fopen(”A:\SZOVEG\NEV.TXT”név”,”mód”);

Az fp mutató értéke NULL, ha az állomány megnyitása sikertelen volt. A fizikai file névben teljes elérési útvonalat is megadhatunk, ebben az esetben azonban ügyelni kell a \ jel használatára:

”A:\SZOVEG\NEV.TXT” helyett ”A:\\SZOVEG\\NEV.TXT”[2]

A mód paraméter azt jelenti, hogy milyen műveleteket akarunk végezni az állománnyal.

 

Mód

Leírás

r (+)

Létező file megynyitása olvasásra. File mutató a file elejére áll.

w (+)

Új file megnyitása írásra. Létező file esetén annak tartalma elvész. . File mutató a file elejére áll.

a (+)

File megnyitása hozzáírásra. Nyitás után a file mutatóa file végére áll. Ha a file nem létezik, akkor az fopen létrehozza

 

Mindegyik mód jellemző kiegészíthető egy + paraméterrel, ez miden esetben azt jelenti, hogy az állományt olvashatjuk és írhatjuk is. A mód sztringben szoktuk még megadni, hogy milyen állománnyal dolgozunk. t szöveges, b bináris állományt jelent.

Nézzünk egy konkrét példát, melyben egy szöveges állományt megnyitunk írásra és olvasásra:

FILE *fp;

fp=fopen(”A:\\SZOVEG\\NEV.TXT”,”r+t”);

if (fp==NULL)

  {

     printf(”Sikertelen file nyitás!”);

     return –1;

  }

A file nyitást gyakra szokták az if-en belülre helyezni. Ekkor a szintaktikája a következő:

if (!(fp=fopen(”A:\\SZOVEG\\NEV.TXT”,”r+t”)))

  {

     printf(”Sikertelen file nyitás!”);

     return –1;

  }

Ha a file-on elvégeztük a megfelelő műveleteket akkor le kell zárni. Ezt az fclose(fp) függvényhívás valósítja meg. Amennyiben egy filban írási műveletekt is végeztünk lezárás előtt célszerű az fflush(fp) függvényhívás, ez az átmeneti pufferek tartalmát kiírja az állományba, ha még nem történt volna meg.

1.1.2    Szöveges állományok

Szöveges állományokkal kapcsolatban leggyakrabban alkalmazott függvényeket az alábbi táblázatban foglajuk össze. Minden esetben a

FILE *fp;

char ch,string[]=”Kiírandó szöveg”;

char sz[20];

definíciókat használjuk

Függvény

Leírás

ch=fgetc(fp)

Beolvas egy karaktert a file-ból

fputc(ch,fp)

Kiír egy karaktert a file-ba

fgets(sz,strlen(string)+1,fp)

Az sz változóba beolvas egy sztringet

fputs(string,fp)

A string változó tartalmát kiírja a file-ba

fscanf(fp,”konv”,&valt)

Hasonló a scanf-hez, eltérés az első paraméterben

fprintf(fp,”konv”,valt

Hasonló a printf-hez, eltérés az első paraméterben

Az alábbiakban két egyszerű programot mutatunk be a szöveges állományok kezelésére:

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

 

main()

{

  char c;

  FILE *fp;

  int i;

 

  clrscr();

 

  if (!(fp=fopen("A:\\Fileok\\p.txt","wt")))

     {

       fprintf(stderr,"Nem sikerült megnyitni az állományt");

       return -1;

     }

 

  for (i=0;i<10;i++)

     fprintf(fp,"%4d",i);

  fflush(fp);

  fclose(fp);

 

  if (!(fp=fopen("A:\\Fileok\\p.txt","rt")))

     {

       fprintf(stderr,"Nem sikerült megnyitni az állományt");

       return -1;

     }

 

  i=0;

  while (!feof(fp))

     {

       fscanf(fp,"%d",&i);

       printf("%d",i);

     }

  fclose(fp);

  while ((c=getch()) !=13);

 

}

A példában egész értékeket írunk ki egy szöveges állományba, majd visszaolvassuk azokat. A visszaolvasásánál a file vége jelölésére az feof(fp) függvényt használjuk. Ez a file végére érve vesz föl NULL értéket.

A másik példa egy állomány nevét kéri be, majd karakterenként kilistázza a képernyőre.

  #include <stdio.h>

  #include <conio.h>

 

  main()

  {

     char nev[25];

     FILE *fp;

     char c;

 

     clrscr();

 

     printf("Állomány neve: ");

     scanf("%24s", nev);

     clrscr();

 

     fp = fopen ( nev, "rt");

 

     if( fp == NULL )

       printf("Nem lehet megnyitni a(z) %s állományt\n", nev);

     else {

         while( (c = fgetc(fp)) != EOF )

            putchar (c);

         fclose (fp);

     }

  }

1.1.3    Bináris állományok

A bináris állományokat byte-onként vagy blokkonként kezelhetjük. A byte-onkénti kezeléshez jól használható az előző részben leírt fgetc és fputc függvénypáros. A blokkonkénti kezelést pedig az fread és az fwrite függvényekkel végezhetjük el.

Használatukat a következő példában figyelhetjük meg.

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

 

main()

{

  char c;

  FILE *bf;

  int i[10]={1,2,3,4,5,6,7,8,9,10},counter,sv;

 

  clrscr();

 

  if (!(bf=fopen("A:\\fileok\\adat.dat","w+b")))

     {

       printf("Sikertelen file nyitás");

       return -1;

     }

 

  fwrite(i,sizeof(int),10,bf);

 

  rewind(bf);

  counter=fread(&sv,sizeof(int),1,bf);

  printf("%4d",sv);

 

  fseek(bf,3*sizeof(int),SEEK_SET); /* A 4. elemre áll  */

  counter=fread(&sv,sizeof(int),1,bf);

  printf("%4d",sv);

 

  fseek(bf,0*sizeof(int),SEEK_CUR); /* A rákövetkezőre áll  */

  counter=fread(&sv,sizeof(int),1,bf);

  printf("%4d",sv);

 

  fclose(bf);

 

  while ((c=getch()) !=13);

 

}

Nézzük először az fwrite függvényt. A függvény első paramétere a kiírandó változó neve, második paramétere az adott struktúrához tartalmazó blokkméret, harmadik paraméter a kiírandó elemek darabszáma, negyedik pedig az állomány mutatója.

Az fread függvény hasonlóképpen paraméterezhető. Eltérés abban van hogy beolvasáskor nyilván a változó címét kell megadni a függvénynek, a másik három paraméter ugyanaz. Természetesen mindkét függvénynek van visszatérési értéke is. Mindkettőnél a sikeresen kiírt illetve beolvasott blokkok számát adja vissza. Ez az érték használható a sikertelen beolvasás illetve kiírás figyelésére. Ha a fenti programban a counter változó értéke nem egyenlő eggyel, akkor az azt jelenti, hogy nem sikerült beolvasni adatot az állományból. Ezeknek a változóknak a megadása nem kötelező, mint a fenti programból is látszik az fwrite függvényt enélkül hívtuk meg.

A progarmban van még egy újdonság, az állományban való pozícionálás. Erre az fseek függvényt használjuk. Paraméterezése: első paraméter a file mutató, második a blokkméret és egy egész szám szorzata (ennyiedik elemre fogunk állni), harmadik pedig azt mutatja meg, hogy mihez viszonytjuk a pozícionálást. SEEK_CUR esetén a pillanatnyi pozícióhoz, SEEK_SET esetén pedig a file elejéhez. Vigyázzunk azonban ennek az alakalmazásával, a sorszámozás most is a nulladik elemtől kezdődik, ennek a SEEK_SET esetén lehet jelentősége. A pillanatnyi pozícióval pedig az a helyzet, hogy amikor egy adat beolvasása megtörtént, akkor a file mutató rögtön eggyel tovább lép, tehát, ha a szomszédos elemre akarunk lépni, akkor természetesen a fseek-ben 0-t kell adnunk a második paraméter helyén[3].



[1] Logikai file név

[2] A string konstansokban a \ jel egy formázó karaktert vezet be.

[3] Ilyet nyilván nem fogunk csinálni, mert automatikus a továbblépés