Επεξεργασία Αρχείων Κειµένου Στην ενότητα αυτή θα µελετηθούν τα εξής επιµέρους θέµατα: Αρχεία Κειµένου Γενικά Συναρτήσεις Επεξεργασίας Αρχείων Κειµένου ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 1
Αρχεία Γενικά Ένα αρχείο για να χρησιµοποιηθεί από ένα πρόγραµµα C πρέπει πρώτα να aνοιχθεί. Αυτό πραγµατοποιείται µέσω της συνάρτησης βιβλιοθήκης fopen(). Η fopen() παίρνει ως όρισµα το όνοµα ενός αρχείου (π.χ. f.txt) και επιστρέφει έναν δείκτη προς αυτό το αρχείο ο οποίος δείκτης χρησιµοποιείται από µία πληθώρα άλλων συναρτήσεων για την ανάγνωση από και εγγραφή δεδοµένων προς το αρχείο αυτό. Ο δείκτης αυτός ονοµάζεται δείκτης σε αρχείο (file pointer) και δηλώνεται ως εξής: FILE *fp; /*Ορίζουµε µία µεταβλητή fp τύπου δείκτη σε αρχείο.*/ Οι δείκτες αρχείων stdin, stdout, stderr έχουν ήδη δηλωθεί στο <stdio.h>. Το stdin αναφέρεται στο πληκτρολόγιο και τα stdout, stderr αναφέρονται στην οθόνη. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 2
Αρχεία Γενικά Η λειτουργικότητα της fopen() περιγράφεται παρακάτω: FILE *fopen(char *name, char *mode): Η συνάρτηση fopen() ανοίγει το αρχείο µε όνοµα name σύµφωνα µε τον τρόπο που θα το χρησιµοποιήσουµε και που περιγράφεται µε το όρισµα mode. Πιθανοί τρόποι είναι ανάγνωση ("r"), εγγραφή ( "w") και επέκταση ( "a"). Αν το αρχείο που ανοίγεται για εγγραφή ήεπέκταση δεν υπάρχει τότε δηµιουργείται. Σε περίπτωση λάθους επιστρέφεται NULL. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 3
Συναρτήσεις Επεξεργασίας Αρχείων Κειµένου Οι βασικές συναρτήσεις επεξεργασίας αρχείων κειµένου περιγράφονται αναλυτικά πιο κάτω: 1. int getc(file *fp) Η συνάρτηση αυτή επιστρέφει τον επόµενο χαρακτήρα από το αρχείο στο οποίο αναφέρεται ο δείκτης fp. Επιστέφει EOF σε περίπτωση τέλους του αρχείου ή λάθους κατά την ανάγνωση. 2. int putc(int c, FILE *fp) Η συνάρτηση αυτή γράφει το χαρακτήρα c στο αρχείο στο οποίο αναφέρεται ο δείκτης fp και επιστρέφει το χαρακτήρα που γράφτηκε ή EOF σε περίπτωση λάθους. 3. int fscanf(file *fp, char format,...) Όµοια µε την scanf() µε τη διαφορά ότι η ανάγνωση γίνεται από το αρχείο στο οποία αναφέρεται ο δείκτης fp. Επιστρέφεται EOF σε περίπτωση λάθους ή τέλος του αρχείου, αλλοιώς επιστρέφεται ο αριθµός των αντικειµένων στα οποία πραγµατοποιήθηκε η ανάγνωση. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 4
Συναρτήσεις Επεξεργασίας Αρχείων Κειµένου 1. int fprintf(file *fp, char format,...) Οµοια µε την printf() µε τη διαφορά ότι η εκτύπωση γίνεται στο αρχείο στο οποίο αναφέρεται ο δείκτης fp. Επιστρέφεται ένας αρνητικός αριθµός σε περίπτωση λάθους ή διαφορετικά το πλήθος των χαρακτήρων που γράφτηκαν στο αρχείο. 2. int fclose(file *fp) Το αρχείο κλείνεται και ελευθερώνεται ο δείκτης fp για επόµενη χρήση. 3. int feof(file *fp) Επιστρέφει µη-µηδενική τιµή σε περίπτωση που έχουµε φτάσει στο τέλος του αρχείου στο οποίο αναφέρεται ο δείκτης fp. ιαφορετικά επιστρέφεται µηδέν. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 5
Αρχεία Γενικά (συν) Σε περίπτωση που θέλουµε να κάνουµε ανάγνωση ή εγγραφή ολόκληρων γραµµών από ένα αρχείο χρησιµοποιούµε τις συναρτήσεις: char *fgets(char *line, int maxline, FILE *fp) Η συνάρτηση αυτή διαβάζει το πολύ maxline 1 χαρακτήρες από το αρχείο και τους τοποθετεί στον πίνακα χαρακτήρων line. Αν βρεί πρώτα τον χαρακτήρα newline σταµατά και δεν διαβάζει όλους τους maxline 1 χαρακτήρες. Ο χαρακτήρας newline τοποθετείται επίσης στον πίνακα line και το string line τερµατίζεται µε το χαρακτήρα \0. Η συνάρτηση επιστρέφει το δείκτη line. ιαφορετικά επιστρέφει την τιµή NULL σε περίπτωση που βρισκόµαστε στο τέλος του αρχείου ή σε περίπτωση λάθους. int *fputs(char *line, FILE *fp) Η συνάρτηση αυτή γράφει το string line (το οποίο δε χρειάζεται να περιέχει το χαρακτήρα newline) στο αρχείο που καθορίζεται από το δείκτη fp. Επιστρέφει έναν µη-αρνητικό αριθµό ή EOF σε περίπτωση λάθους. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 6
Αρχεία Γενικά (συν) Υπενθύµιση. Στη C κάθε ανάθεση, όπως π.χ. η c = getchar() θεωρείται ως µία έκφραση η οποία έχει τιµή. Η τιµή κάθε ανάθεσης ως έκφραση ισούται µε την τιµή του ΑΡΙΣΤΕΡΟΥ µέλους µετά την εκτέλεση της ανάθεσης. ηλαδή, η τιµή της ανάθεσης c = getchar() είναι η τιµή της µεταβλητής cµετά την εκτέλεση της ανάθεσης. Προσέξτε την παρακάτω συνάρτηση αντιγραφής αρχείων: void filecopy(file *ifp, FILE *ofp){ char c; /* µη ασφαλής δήλωση!! */ while ((c = getc(ifp))!= EOF) putc(c, ofp); } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 7
Αρχεία Γενικά (συν) Το παραπάνω πρόγραµµα έχει µία ατέλεια. Σε πολλές αρχιτεκτονικές ο τύπος char αναφέρεται στην αποθήκευση χαρακτήρων που δίνονται από το πληκτρολόγιο και αποθηκεύει µόνο θετικές τιµές που αντιπροσωπεύουν τον κωδικό κάθε χαρακτήρα. Η συνάρτηση getc() όµως σε περίπτωση τέλους του αρχείου επιστρέφει EOF που η τιµή του είναι (συχνά) -1. Η τιµή όµως αυτή δεν µπορεί να αναπαρασταθεί µέσω του τύπου char (σε ορισµένες πάντα αρχιτεκτονικές) και συνεπώς η σύγκριση του while ποτέ δεν θα γίνει αληθής!!!! Η παραπάνω υλοποίηση της συνάρτησης θα είναι συνεπώς σε πολλές αρχιτεκτονικές λάθος. Μία ασφαλή υλοποίηση τέτοιων συναρτήσεων πρέπει να χρησιµοποιεί τη δήλωση µεταβλητών για χαρακτήρες κάνοντας χρήση του τύπου int. Θα ορίζουµε λοιπόν int c; για µία µεταβλητή τύπου χαρακτήρα σε παρόµοιες περιπτώσεις ώστε τα προγράµµατά µας να εκτελούνται σωστά σε όλες τις αρχιτεκτονικές. ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 8
Παράδειγµα... Να γραφεί ένα πρόγραµµα το οποίο παίρνει n ορίσµατα (εκτός από το όνοµα του προγράµµατος) όλα από τα οποία είναι ονόµατα αρχείου και και κατά την κλήση του αντιγράφει τα n-1 πρώτα αρχεία στο τελευταίο.ορ. Για παράδειγµα αν το πρόγραµµα αυτό λέγεται copy, τότε µία κλήση της µορφής: $ copy f1.txt f2.txt f3.txt f4.txt Θα δηµιουργούσε ένα αρχείο f4.txt το οποίο θα είχε ως περιεχόµενα τα περιεχόµενα των f1.txt, f2.txt και f3.txt µαζί. Οι τυπικές παράµετροι της συνάρτησης main θα έχουν τιµές: argc = 5 argv[0] = copy argv[1] = f1.txt argv[2] = f2.txt argv[3] = f3.txt argv[4] = f4.txt argv[5] = ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 9
Παράδειγµα... (συν) #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i, ch; FILE *inp, *outp; if (argc < 2) { printf( Λάθος σύνταξη στη χρήση του προγράµµατος... \n ); exit(1); } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 10
Παράδειγµα... (συν) outp = fopen(argv[argc-1], w ); for ( i=1; i < argc-1; i++) { inp = fopen(argv[i], r ); for (ch=getc(inp); ch!= EOF; ch=getc(inp)) putc(ch,outp); fclose(inp); } fclose(outp); printf( All files copied to %s\n, argv[argc-1]); return(0); } ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 11