Βιβλιοθήκη 1 lalis@inf.uth.gr
Σύνοψη Ορίστηκε από τον Dennis Ritchie το 1975 Μέρος του προτύπου ANSI C Λειτουργίες εισόδου/εξόδου υψηλού επίπεδου και ανεξάρτητες λειτουργικού συστήματος Υποστήριξη για διάβασμα/γράψιμο τιμών δεδομένων βασικού τύπου από/σε αρχεία/ροές χαρακτήρων Χρησιμοποιεί εσωτερική αποθήκη δεδομένων Χρησιμοποιεί, εσωτερικά, τις αντίστοιχες κλήσεις συστήματος open, read, write, close, 2 lalis@inf.uth.gr
εφαρμογή (application) fopen, fread, fwrite, fclose, βιβλιοθήκη open, read, write, close, αποθήκη κώδικας συστήματος user system 3 lalis@inf.uth.gr
Βασικές λειτουργίες (1) FILE *fopen(const char *name, const char * mode); ανοίγει το αρχείο με όνομα name, δημιουργεί μια αντίστοιχη δομή πρόσβασης FILE, και επιστρέφει ένα δείκτη σε αυτή Η επιθυμητή πρόσβαση ορίζεται μέσω mode r: ανάγνωση υπάρχοντος αρχείου w: δημιουργία νέου αρχείου για γράψιμο (αν ήδη υπάρχει τότε τα προηγούμενα περιεχόμενα διαγράφονται) a: γράψιμο/προσθήκη στο τέλος του αρχείου r+: όπως r αλλά με γράψιμο w+: όπως w αλλά με ανάγνωση a+: όπως a αλλά με ανάγνωση 4 lalis@inf.uth.gr
Βασικές λειτουργίες (2) int fscanf(file *stream, const char *format,...) μορφοποιημένη ανάγνωση στο πνεύμα της scanf int fprintf(file *stream, const char *format,...) μορφοποιημένη εγγραφή στο πνεύμα της printf char *fgets(char *restrict s, int n, FILE *stream); ανάγνωση μιας ολόκληρης γραμμής που τερματίζεται με \n int fflush(file *stream); άδειασμα αποθήκης δεδομένων (για αρχεία δίσκου: αποθήκευση) int fclose(file *stream); κλείσιμο και απελευθέρωση πόρων/αποθήκης 5 lalis@inf.uth.gr
Καθιερωμένη είσοδος/έξοδος Υπάρχουν οι καθιερωμένοι περιγραφείς αρχείων για είσοδο (STDIN_FILENO), έξοδο (STDOUT_FILENO), και έξοδο λαθών (STDERR_FILENO) Η συνδέει αυτούς τους περιγραφείς με αντίστοιχους δείκτες σε δομές FILE *stdin, *stdout, *stderr Προσφέρει ειδικές συναρτήσεις εισόδου/εξόδου ειδικά για την καθιερωμένη είσοδο/έξοδο printf/scanf (στο πνεύμα των fscanf/fprintf) απλά γράφουν/διαβάζουν στην καθιερωμένη έξοδο/είσοδο 6 lalis@inf.uth.gr
Εσωτερική αποθήκη Η διατηρεί τους χαρακτήρες που προορίζονται για γράψιμο ή ανάγνωση σε εσωτερική αποθήκη Ξεχωριστή αποθήκη για κάθε δομή FILE γράψιμο: τα δεδομένα γράφονται προσωρινά στην αποθήκη και μεταφέρονται αυτόματα στο αρχείο/ροή όταν γεμίσει η αποθήκη ή όταν ζητηθεί ρητά άδειασμα της αποθήκης διάβασμα: τα δεδομένα μεταφέρονται στην αποθήκη, και από εκεί διαβάζονται όταν αυτό ζητηθεί από το πρόγραμμα Η εσωτερική αποθήκη δημιουργείται αυτόματα κατά την πρώτη κλήση ανάγνωσης ή εγγραφής Μείωση των κλήσεων συστήματος (write/read) ακόμα και όταν το πρόγραμμα διαβάζει/χειρίζεται τα δεδομένα byte-με-byte (χαρακτήρα-με-χαρακτήρα) 7 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); 8 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); fd=open("", O_RDWR Ο_CREAT,S_IRWXU); f=(file *)malloc( ); f->fd=fd; 9 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f);???????????????????????????????? f->buf(char*)=malloc(bufsize); f->blen=0; 10 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f);?????????????????????? cpy(&f->buf[f->blen],str1,len(str1)); f->blen+=len(str1); 11 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); 20???????????????????? f->buf[f->blen]=' '; f->blen+=1; 12 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); 20 77 72 6C 64?????????? cpy(&f->buf[f->blen],str2,len(str2)); f->blen+=len(str2); 13 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); 20 77 72 6C 64?????????? cpy(&f->buf[f->blen],str2,len(str2)); f->blen+=len(str2); 14 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); 20 77 72 6C 64?????????? write(fd,f->buf,f->blen); fsync(fd); 20 77 72 6C 64 15 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); f->blen=0; 20 77 72 6C 64?????????? 20 77 72 6C 64 16 lalis@inf.uth.gr
char str1[]="hello"; char str2[]="world"; 00 77 72 6C 64 00 f=fopen("","w+"); fprintf(f,"%s ",str1); fprintf(f,"%s",str2); fflush(f); close(f->fd); free(f->buf); free(f); 20 77 72 6C 64?????????? 20 77 72 6C 64 17 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64 18 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); fd=open("", O_RDONLY,0); f=(file *)malloc( ); f->fd=fd; 20 77 72 6C 64 19 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2);???????????????????????????????? f->buf(char*)=malloc(bufsize); f->blen=0; f->bpos=0; 20 77 72 6C 64 20 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? f->blen=read(f->fd,f->buf,bufsize); 20 77 72 6C 64 21 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? f->blen=read(f->fd,f->buf,bufsize); 20 77 72 6C 64 22 lalis@inf.uth.gr
char str1[6]; char str2[6]; h e l l o?????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? k=fnddelimiter(f->buf,f->bpos,f->blen); cpy(str1,f->buf[f->bpos],k); f->pos+=k; 20 77 72 6C 64 23 lalis@inf.uth.gr
char str1[6]; char str2[6]; h e l l o \0???????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? str1[k]='\0'; f->bpos=skipspace(f->buf,f->bpos,f->blen); 20 77 72 6C 64 24 lalis@inf.uth.gr
char str1[6]; char str2[6]; h w e l l o \0 o r l d?? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? k=fnddelimiter(f->buf,f->bpos,f->blen); cpy(str2,f->buf[f->bpos],k); f->pos+=k; 20 77 72 6C 64 25 lalis@inf.uth.gr
char str1[6]; char str2[6]; h w e l l o \0 o r l d \0 f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); 20 77 72 6C 64?????????? str2[k]='\0'; f->bpos=skipspace(f->buf,f->bpos,f->blen); 20 77 72 6C 64 26 lalis@inf.uth.gr
char str1[6]; char str2[6];???????????????????????? f=fopen("","r"); fscanf(f,"%s",str1); fscanf(f,"%s",str2); close(f->fd); free(f->buf); free(f); 20 77 72 6C 64?????????? 20 77 72 6C 64 27 lalis@inf.uth.gr
Χειρισμός κενών κατά την ανάγνωση Η fscanf θεωρεί πως τα δεδομένα της ροής/αρχείου διαχωρίζονται από ένα ή περισσότερα κενά Τα κενά αγνοούνται στην επιστροφή/αποθήκευση των δεδομένων στις μεταβλητές που δίνει ο χρήστης Σε strings προστίθεται αυτόματα το τερματικό (\0) χωρίς αυτό να υπάρχει στην ροή/αρχείο δεδομένων Για διάβασμα των «αυτούσιων» τα περιεχομένων μιας γραμμής, μπορεί να χρησιμοποιηθεί η fgets που διαβάζει μια ολόκληρη γραμμή μέχρι το \n χρησιμοποιείται σε συνδυασμό με την sscanf 28 lalis@inf.uth.gr
Πολιτική εσωτερικής αποθήκευσης Υποστηρίζονται 3 διαφορετικές πολιτικές Line buffered: άδειασμα σε \n Fully buffered: άδειασμα όταν η αποθήκη γεμίσει Not buffered: χωρίς ενδιάμεση αποθήκευση Η βιβλιοθήκη θέτει αυτόματα την πολιτική αποθήκευσης, ανάλογα με την περίπτωση Καθιερωμένη είσοδος/έξοδος: line buffered Καθιερωμένη έξοδος λαθών: not buffered Αρχεία δίσκου: fully buffered 29 lalis@inf.uth.gr
Αλλαγή πολιτικής αποθήκευσης Ο προγραμματιστής μπορεί να προσδιορίσει ρητά την επιθυμητή πολιτική αποθήκευσης, για κάθε FILE int setvbuf(file *stream, char *buffer, int mode, size_t size); Καθορίζει την πολιτική αποθήκευσης, το μέγεθος της αποθήκης ή/και την ίδια την αποθήκη Η λειτουργία setvbuf πρέπει να κληθεί μετά την fopen αλλά προτού κληθεί η πρώτη λειτουργία εισόδου/εξόδου 30 lalis@inf.uth.gr
int main(int argc, char *argv[]) { char str[]="hello world\n"; int i; } if (argc > 1) { not buffered if (argv[1][0] == 'n') { setvbuf(stdout,null,_ionbf,0); } else if (argv[1][0] == 'f') { setvbuf(stdout,null,_iofbf,0); } } fully buffered printf("start printing\n"); for (i=0; i<strlen(str); i++) { sleep(1); printf("%c",str[i]); } return(0); 31 lalis@inf.uth.gr
Ανακατεύθυνση και Η χρήση της βιβλιοθήκης με ανακατεύθυνση της ΕΕ σε αρχεία δεν είναι εντελώς διαφανής λόγω της πολιτικής ενδιάμεσης αποθήκευσης Αν η χρησιμοποιηθεί σε πρώτη φάση με την καθιερωμένη είσοδο/έξοδο να δείχνει στην συσκευή τερματικού, η πολιτική είναι line buffered ακόμα και αν ακολουθήσει ανακατεύθυνση σε αρχείο Αν η χρησιμοποιηθεί σε πρώτη φάση με την καθιερωμένη είδοσο/έξοδο να δείχνει ήδη σε αρχεία, η πολιτική είναι fully buffered για να γραφτούν δεδομένα στο αρχείο πρέπει να ζητηθεί ρητά το άδειασμα της ενδιάμεσης αποθήκης με fflush 32 lalis@inf.uth.gr
int fd; fully buffered fd=open("",o_wronly O_CREAT O_TRUNC,S_IRWXU); dup2(fd,stdout_fileno); /* redirect stdout to fd */ printf("hello world\n"); int fd; line buffered printf("something to set policy to line-buffered\n"); fd=open("",o_wronly O_CREAT O_TRUNC,S_IRWXU); dup2(fd,stdout_fileno); /* redirect stdout to fd */ printf("hello world\n"); 33 lalis@inf.uth.gr