8 Súbory
Okrem práce so štandardnými vstupnými a výstupnými zariadeniami je možné vykonávať zápis a čítanie informácií zo súborov. Táto činnosť je podporovaná dvoma skupinami štandardných funkcií pre dve úrovne práce so súbormi.
Nižšiu úroveň reprezentuje skupina funkcií, ktoré priamo využívajú služby operačného systému. Celú réžiu s tým spojenú musí zabezpečovať samotný program.
Vyššiu úroveň predstavuje práca s prúdmi (stream) údajov. Táto úroveň sa používa najčastejšie a je užívateľsky prijateľnejšia ako prv spomínaná nižšia úroveň.
Každá činnosť spojená s komunikáciou so súborom môže pozostávať z týchto krokov :
- otvorenie súboru
- manipulácia so súborom (čítanie, zápis, nastavenie)
- zatvorenie súboru
Pri práci so súbormi sa stretávame s niektorými preddefinovanými konštantami :
EOF | koniec súboru |
FOPEN_MAX | maximálny počet súčasne otvorených súborov |
FILENAME_MAX | maximálna dĺžka názvu súboru |
TMP_MAX | maximálny počet súčasne otvorených pracovných prúdov |
8.1 Práca s prúdmi (stream I/O)
Je charakteristická použitím dátového typu FILE pre identifikáciu súboru. Tento typ (presnejšie smerník na typ) obsahuje všetky informácie o spracovávanom prúde. Užívateľ, ktorý chce pracovať s týmto typom, musí pre svoj súbor deklarovať premennú typu FILE * (vždy veľkými písmenami), v ktorej budú udržované informácie o danom prúde. Inicializácia tejto štruktúry sa vykonáva pri vytváraní alebo otváraní prúdu, spätný prenos sa uskutoční pri uzatváraní prúdu. Štandardné zariadenia vstupu - výstupu podľa kap. 7 sú deklarované tiež ako prúdy v tvare :
FILE *stdin FILE *stdout FILE *stderr
Podľa spôsobu práce existujú dva režimy prúdov - textový a binárny. Voľba režimu prúdu je vecou užívateľa v závislosti na charaktere úlohy. V textovom režime sa pomocou príslušných knižničných funkcií čítajú a zapisujú obyčajné textové riadky, kým v binárnom režime sa jedná o vnútorný tvar zápisu. Obsah binárneho súboru nie je funkciami čítania - zápisu nijako ovplyvňovaný. Práca s binárnym súborom je rýchlejšia a zaberá menej miesta v pamäti. Textový súbor je však na druhej strane možno prezerať, resp. i vytvárať bežnými prostriedkami (editormi). Je nutné poznamenať, že aj tu je rozdiel pri použití kompilátora. No najväčší rozdiel je cítiť pri prechode medzi rôznymi platformami (pod UNIX-om nie je žiaden rozdiel medzi textovým a binárnym režimom).
Pre otvorenie prúdu je k dispozícii funkcia:
FILE *fopen(const char *name, const char *mode);
name - | názov otváraného (vytváraného) súboru |
mode - |
r textový súbor čítanie w textový súbor zápis a textový súbor pripojenie na koniec rb binárny súbor čítanie wb binárny súbor zápis r+ textový súbor čítanie a zápis w+ textový súbor zápis a+ textový súbor čítanie a zápis na koniec ab binárny súbor pripojenie na koniec rb+ binárny súbor čítanie a zápis wb+ binárny súbor zápis ab+ binárny súbor čítanie a zápis na koniec |
Ak je operácia otvorenia úspešná, vráti funkcia smerník na daný súbor, pomocou ktorého ďalej so súborom pracujeme. V opačnom prípade vráti hodnotu NULL, ktorú je možné i potrebné testovať.
Test na koniec súboru pri práci s prúdmi namiesto kombinácie EOF využíva funkciu
int feof(FILE *stream)
ktorá vracia hodnotu != 0 (true), ak je aktuálna pozícia nastavená na koniec prúdu. V opačnom prípade vracia hodnotu 0 (false).
Na zatvorenie súboru (po skončení práce s daným súborom) je k dispozícii funkcia :
int fclose(FILE *stream);
Pre ďalšiu prácu s prúdmi platí všetko, čo bolo uvedené v kap. 6 pre štandardný vstup - výstup s tým, že sa to vzťahuje na príslušný prúd. Pre prácu so znakmi sú k dispozícii funkcie :
int getc(FILE *stream); int ungetc(int c,FILE *stream); int putc(int c,FILE *stream);
Nová je funkcia ungetc, ktorá umožňuje vrátiť prečítaný znak späť do prúdu. Vstup a výstup reťazcov podporujú funkcie :
char *fgets(char *string, FILE *stream); int fputs(char *string, FILE *stream);
Podobne formátovaný vstup - výstup podporujú funkcie :
int fprintf(FILE *stream,char *format,arg1,arg2,...,argn); int fscanf(FILE *stream,char *format, &arg1,&arg2,...,&argn);
Ďalej sú k dispozícii funkcie pre vstup - výstup celých čísel :
int getw(FILE *stream); int putw(int i, FILE *stream);
a pre prenos údajov po blokoch :
int fread(char *buffer,int size,int count,FILE *stream); int fwrite(char *buffer,int size,int count,FILE *stream); cez pole buffer. Veľkosť bloku je (size x count).
Pre nastavenie pozície v súbore, od ktorej sa bude čítať, resp. zapisovať, slúži funkcia :
int fseek(FILE *stream,long int offset,int mode);
offset - | veľkosť posunu v súbore od pozície, danej parametrom mode |
mode - |
SEEK_SET od začiatku súboru SEEK_CUR od aktuálnej pozície v súbore SEEK_END od konca súboru |
Aktuálnu pozíciu v súbore je možné zistiť pomocou funkcie :
long int ftell(FILE *stream);
Uchovanie a obnovenie aktuálnej pozície v súbore pomocou dátovej štruktúry preddefinovaného typu fpos_t umožňujú funkcie :
int fgetpos(FILE *stream, fpos_t *position); int fsetpos(FILE *stream, const fpos_t *position);
Pre prácu so súbormi typu stream je k dispozícii ešte celý rad ďalších funkcií pre testovanie vzniku chyby, vyprázdnenie bufra, nastavenie na začiatok súboru, riadenie práce s prúdom, chybové správy (podrobne viď popis knižnice jazyka C). Spoločným znakom všetkých týchto funkcií je to, že všetky sa začínajú písmenom "f" a všetky pracujú s identifikátorom súboru typu FILE *.
8.2 Práca so súbormi na nižšej úrovni (basic I/O)
Podstatným aj formálnym rozdielom pri práci so súbormi na nižšej úrovni vzhľadom na súbory typu stream je použitie identifikátora súboru typu int (tzv. manipulačné číslo) namiesto FILE *, pomocou ktorého pracujeme so súborom v jednotlivých štandardných funkciách.
Pre otvorenie súboru je k dispozícii funkcia :
int open(char *name,int mode); kde name - meno súboru mode - prístup k súboru (čítanie, zápis, oboje) (podrobne viď popis knižnice jazyka)
Funkcia vracia celé číslo - identifikátor súboru v prípade úspešného otvorenia, v opačnom prípade vracia -1. Tento identifikátor (handle) potom je používaný vo všetkých ďalších funkciách.
Pre zatvorenie súboru je k dispozícii funkcia :
int close(int handle);
Čítanie a zápis do súboru sa realizuje funkciami read a write s využitím bufra a jeho veľkosti v tvare :
int read(int handle,char *buffer,int size); int write(int handle,char *buffer,int size); kde handle identifikátor súboru buffer názov bufra size dĺžka bufra
Nastavenie pozície v súbore je možné s využitím funkcie :
int lseek(int handle,long int offset,int mode);
ktorá je úplne analogická vyššie popísanej funkcii fseek.
8.3 Parametre programu
V jazyku C je definovaná možnosť dovozu parametrov do programu pri jeho spustení. Na tento účel sa využíva hlavička programu s dvoma parametrami v tvare :
void main(int argc, char *argv[]) kde argc skutočný počet parametrov dovážaných do programu, zväčšený o 1 argv[] pole reťazcov, obsahujúcich jednotlivé dovážané parametre argv[0] obsahuje názov programu, argv[1] prvý parameter, atď.
Príklad použitia uvedeného aparátu viď v nasledujúcej kapitole.
8.4 Príklady práce so súbormi
Uvedená príklady riešia postupne formátovaný výstup do súboru, výstup zo súboru po znakoch, čítanie zo súboru po znakoch, čítanie zo súboru po slovách, po riadkoch, tlač súboru na tlačiareň, kopírovanie súborov a rôzne ich kombinácie, nastavovanie i vyhľadávanie pozície v súbore. Časť príkladov pracuje s pevne zadanými názvami súborov, druhá časť je univerzálnejšia - názvy súborov sú prenášané formou parametrov (viď kap. 8.3).
/* priklad pr8_1.c formatovany vystup */
#include <stdio.h>
void main(void)
{
FILE *fp;
char stuff[25];
int index;
fp = fopen("S.TXT","w"); /* open for writing */
strcpy(stuff,"To je riadok.");
for (index = 1;index <= 10;index++)
fprintf(fp,"%s Cislo riadku %d\n",stuff,index);
fclose(fp); /* close the file before ending program */
}
/* priklad pr8_2.c vystup po znakoch */
#include "stdio.h"
void main(void)
{
FILE *fp;
char others[35];
int indexer,count;
strcpy(others,"Pridane riadky.");
fp = fopen("s.txt","a"); /* open for appending */
for (count = 1;count <= 5;count++)
{
for (indexer = 0;others[indexer];indexer++)
/* kym others[indexer] != 0 */
putc(others[indexer],fp); /* output a single character */
putc('\n',fp); /* output a linefeed */
}
fclose(fp);
}
/* priklad pr8_3.c citanie po znakoch */
#include "stdio.h"
void main(void)
{
FILE *fp;
char c;
fp = fopen("S.TXT","r");
if (fp == NULL) printf("File S.TXT doesn't exist\n");
else
{
do
{
c = getc(fp); /* get one character from the file */
putchar(c); /* display it on the monitor */
} while (c != EOF); /* repeat until EOF (end of file) */
}
fclose(fp);
}
/* priklad pr8_4.c citanie po znakoch a cislovanie riadkov (posledny riadok nie) */
#include "stdio.h"
void main(void)
{
FILE *fp;
char c;
int pocet=1;
fp = fopen("S.TXT","r");
if (fp == NULL) printf("File S.TXT doesn't exist\n");
else
{
printf("%d: ",pocet);
do
{
c = getc(fp); /* get one character from the file */
if(c=='\n')
{
c=getc(fp);
if(feof(fp)==0) printf("\n%d: ",++pocet);
ungetc(c,fp);
}
else putchar(c); /* display it on the monitor */
} while (feof(fp) == 0); /* repeat until end of file */
}
fclose(fp);
}
/* priklad pr8_5.c citanie po slovach */
#include "stdio.h"
void main(void)
{
FILE *fp;
char oneword[100];
char c;
fp = fopen("S.TXT","r");
if (fp == NULL) printf("File S.TXT doesn't exist\n");
else
{
do
{
c = fscanf(fp,"%s",oneword); /* get one word from the file */
printf("%s\n",oneword); /* display it on the monitor */
} while (c != EOF); /* repeat until EOF (end of file) */
}
fclose(fp);
}
/* priklad pr8_6.c spravne citanie po slovach */
#include "stdio.h"
void main(void)
{
FILE *fp;
char oneword[100];
char c;
fp = fopen("S.TXT","r");
if (fp == NULL) printf("File S.TXT doesn't exist\n");
else
{
do
{
c = fscanf(fp,"%s",oneword); /* get one word from the file */
if(c != EOF) printf("%s\n",oneword); /* display it on the monitor */
} while (c != EOF); /* repeat until EOF (end of file) */
}
fclose(fp);
}
/* priklad pr8_7.c citanie po riadkoch */
#include "stdio.h"
void main(void)
{
FILE *fp;
char oneword[100];
char *c;
fp = fopen("S.TXT","r");
if (fp == NULL) printf("File S.TXT doesn't exist\n");
else
{
do
{
c = fgets(oneword,100,fp); /* get one word from the file */
if(c != NULL) printf("%s",oneword); /* display it on the monitor */
} while (c != NULL); /* repeat until EOF (end of file) */
}
fclose(fp);
}
/* priklad pr8_8.c citanie po slovach so zadanim nazvu suboru */
#include "stdio.h"
void main(void)
{
FILE *fp;
char oneword[100],filename[25];
char *c;
printf("Enter filename: ");
scanf("%s",filename);
fp = fopen(filename,"r");
if (fp == NULL) printf("File [%s] doesn't exist\n",filename);
else
{
do
{
c = fgets(oneword,100,fp); /* get one word from the file */
if(c != NULL) printf("%s\n",oneword); /* display it on the monitor */
} while (c != NULL); /* repeat until EOF (end of file) */
}
fclose(fp);
}
/* priklad pr8_9.c tlac suboru po znakoch na tlaciaren */
#include "stdio.h"
void main(void)
{
FILE *fp,*printer;
char fname[25];
char c;
printf("Enter filename: ");
scanf("%s",filename);
fp = fopen(filename,"r");
printer=fopen("$LPT","w");
/* printer=fopen("PRN","w"); pre DOS */
if (fp == NULL) printf("File doesn't exist\n");
else if (printer==NULL)printf("PRN doesn't exist\n");
else
{
do
{
c = fgetc(fp); /* get one character from the file */
if (c != EOF)
{
putchar(c);
putc(c,printer);
}
} while (c != EOF); /* repeat until EOF (end of file) */
}
fclose(fp);
fclose(printer);
}
/* priklad pr8_10.c citanie po slovach
so zadanim nazvu suboru cez parametre*/
#include "stdio.h"
void main(int argc, char *argv[])
{
FILE *fp;
char oneword[100];
char *c;
if(argc==1) printf("Volanie: %s filename\n",argv[0]);
else
{
if(argc > 2)printf("Pozor! Spracuje sa iba 1. parameter!\n");
fp = fopen(argv[1],"r");
if (fp == NULL) printf("File [%s] doesn't exist\n",argv[1]);
else
{
do
{
c = fgets(oneword,100,fp); /* get one word from the file */
if(c != NULL)
printf("%s",oneword); /* display it on the monitor */
} while (c != NULL); /* repeat until EOF (end of file) */
}
fclose(fp);
}
}
/* priklad pr8_11.c cislovanie riadkov
so zadanim nazvu suboru cez parametre*/
#include "stdio.h"
#define MAX 80
void main(int argc, char *argv[])
{
FILE *fp;
char line[MAX];
int ln;
if (argc == 1) printf("Volanie: %s filename\n",argv[0]);
else
{
if (argc > 2)printf("Pozor! Spracuje sa iba 1. parameter!\n");
fp = fopen(*++argv,"r");
if (fp == NULL)
{
printf("Can't open [%s]\n",*argv);
exit();
}
else
{
ln=0;
while (fgets(line,MAX,fp)) /* get one line from the file */
printf("%3d : %s",++ln,line);
fclose(fp);
}
}
}
/* priklad pr8_12.c kopirovanie so zadanim
nazvov suborov cez parametre*/
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAXB 512
void main(int argc, char *argv[])
{
char buf[MAXB];
int in,out,lng;
if (argc == 1) printf("Volanie: %s file1 file2\n",argv[0]);
else if (argc == 2)printf("Volanie: %s file1 file2\n",argv[0]);
else
{
if((in=open(*++argv,O_RDONLY)) == -1)
{
printf("Can't open [%s]\n",*argv);
exit();
}
if((out=open(*++argv,O_CREAT|O_RDWR,S_IWRITE)) == -1)
{
printf("Can't open [%s]\n",*argv);
exit();
}
while((lng=read(in,buf,MAXB)) > 0) write(out,buf,lng);
close(in);
close(out);
}
}
/* priklad pr8_13.c zapis a citanie v rezime text,
binarny a na nižšej úrovni IO
porovnanie prístupu k súboru */
#include "stdio.h"
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
void main(void)
{
FILE *fp;
char c[2];
int pocet=1,h;
fp = fopen("SS.TXT","w");
if (fp == NULL) printf("File SS.TXT doesn't exist\n");
else
{
fprintf(fp,"%d",pocet);
fclose(fp);
}
fp = fopen("SS.TXT","rb");
if (fp == NULL) printf("File SS.TXT doesn't exist\n");
else
{
fscanf(fp,"%d",&pocet);
fclose(fp);
}
printf("Pocet (text) = %d\n",pocet);
fp = fopen("SS.TXT","rb");
if (fp == NULL) printf("File SS.TXT doesn't exist\n");
else
{
fread(c,sizeof(pocet),1,fp);
fclose(fp);
}
sscanf(c,"%d",&pocet);
printf("Pocet (blok) = %d c=%c%c\n",pocet,c[0],c[1]);
h = open("SS.TXT",O_RDONLY);
if (h == -1) printf("File SS.TXT doesn't exist\n");
else
{
read(h,c,sizeof(pocet));
close(h);
}
sscanf(c,"%d",&pocet);
printf("Pocet (IO uroven) = %d c=%c%c\n",pocet,c[0],c[1]);
}
/* priklad pr8_14.c zapis do suboru p.txt
so zadanim nazvu suboru cez parametre*/
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAX 10
void main(int argc, char *argv[])
{
int in,out,lng;
int pocet=1,min=1,max=99;
float x[MAX],y[MAX];
for(lng=0;lng<MAX;lng++)
{
x[lng]=lng+1;
y[lng]=2.5+lng;
}
if (argc == 1) printf("Volanie: %s file1 file2\n",argv[0]);
else if(argc == 2) printf("Volanie: %s file1 file2\n",argv[0]);
else
{
if ((in = open(*++argv,O_RDONLY)) == -1)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
if((out=open(*++argv,O_CREAT|O_TRUNC|O_BINARY,S_IWRITE)) == -1)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
write(out,&pocet,sizeof(pocet));
write(out,&min,sizeof(min));
write(out,&max,sizeof(max));
for(lng=0;lng<MAX;lng++)
{
write(out,&x[lng],sizeof(float));
write(out,&y[lng],sizeof(float));
printf("i=%d x=%f y=%f\n",lng,x[lng],y[lng]);
}
close(in); close(out);
}
}
/* priklad pr8_15.c zapis do suboru nacitanim z 2 suborov
so zadanim nazvu suboru cez parametre
1.subor - vytvoreny ulohou pr8_14 (p.txt)
2.subor - ASCII, pocet+1 riadkov (p1.txt)
3.subor - kombinacia 1. a 2.suboru (p2.txt) */
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAX 50
void main(int argc, char *argv[])
{
FILE *in2;
int in1,out,lng;
int pocet,min,max;
float x,y;
char line[MAX];
if (argc < 4) printf("Volanie: %s file1 file2 file3\n",argv[0]);
else
{
if ((in1 = open(*++argv,O_RDONLY)) == -1)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
if ((in2 = fopen(*++argv,"r")) == NULL)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
if((out=open(*++argv,O_CREAT|O_TRUNC,S_IWRITE)) == -1)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
read(in1,&pocet,sizeof(pocet));
read(in1,&min,sizeof(min));
read(in1,&max,sizeof(max));
write(out,&pocet,sizeof(pocet));
write(out,&min,sizeof(min));
write(out,&max,sizeof(max));
for(lng=0;lng<pocet+1;lng++)
{
fgets(line,MAX,in2);
min=strlen(line);
write(out,&min,sizeof(int));
write(out,line,strlen(line));
}
min=0;
while((lng=read(in1,&x,sizeof(float)))>0)
{
read(in1,&y,sizeof(float));
printf("%d x=%f y=%f\n",min++,x,y);
write(out,&x,sizeof(float));
write(out,&y,sizeof(float));
}
close(in1);
fclose(in2);
close(out);
}
}
/* priklad pr8_16.c citanie zo suboru
so zadanim nazvu suboru cez parametre
vytvoreneho ulohou pr8_15 */
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAX 50
void main(int argc, char *argv[])
{
int in1,lng;
int pocet,min,max;
float x,y;
char line[MAX];
if (argc == 1) printf("Volanie: %s file1\n",argv[0]);
else if (argc > 2) printf("Volanie: %s file1\n",argv[0]);
else
{
if((in1=open(*++argv,O_RDONLY)) == -1)
{
perror("Error ");
printf("Can't open [%s]\n",*argv);
exit();
}
read(in1,&pocet,sizeof(pocet));
read(in1,&min,sizeof(min));
read(in1,&max,sizeof(max));
printf("Pocet = %d\n",pocet);
printf("Min = %d Max = %d\n",min,max);
for(lng=0;lng<pocet+1;lng++)
{
read(in1,&min,sizeof(int));
read(in1,line,min);
line[min]='\0';
printf("%d. %s",lng,line);
}
while((lng=read(in1,&x,sizeof(float)))>0)
{
read(in1,&y,sizeof(float));
printf("x,y: %f %f\n",x,y);
}
close(in1);
}
}
/* priklad pr8_17.c citanie
zo suboru vytvoreneho ulohou p7_13 (p2.txt)
prikazy tell a seek */
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAX 50
void main(void)
{
int in1,lng;
int pocet,min,max;
float x,y;
char line[MAX];
if ((in1 = open("p2.txt",O_RDONLY)) == -1)
{
perror("Error ");
printf("Can't open [p2.txt]\n");
exit();
}
read(in1,&pocet,sizeof(pocet));
read(in1,&min,sizeof(min));
read(in1,&max,sizeof(max));
printf("Pocet = %d\n",pocet);
printf("Min = %d Max = %d\n",min,max);
max=tell(in1);
printf("Poloha 1 v subore je %d\n",max);
for(lng=0;lng<pocet+1;lng++)
{
read(in1,&min,sizeof(int));
read(in1,line,min);
line[min]='\0';
printf("%d. %s",lng,line);
}
printf("Poloha 2 v subore je %d\n",tell(in1));
lseek(in1,max,SEEK_SET);
printf("Poloha (SEEK_SET) v subore je %d\n",tell(in1));
lseek(in1,0L,SEEK_CUR);
printf("Poloha (SEEK_CUR) v subore je %d\n",tell(in1));
lseek(in1,0L,SEEK_END);
printf("Poloha (SEEK_END) v subore je %d\n",tell(in1));
close(in1);
}