Η C είναι απλή/Είσοδος/Έξοδος από/προς αρχεία - File I/O

Από Βικιβιβλία

Θα έρθει η ώρα που θα θέλετε να μπορεί ο χρήστης του προγράμματος σας( ή εσείς ) να αλλάξει κάτι στην εκτέλεσή του, πχ τις τιμές ενός μεγάλου πίνακα δεδομένων, χωρίς όμως να χρειάζεται να τις δίνει μέσω της κονσόλας συνέχεια ή να αλλάζει το πρόγραμμα και να το μεταγλωττίζει ξανά. Αυτό θα το έκανε επεκτάσιμο και εύκολο στη χρήση.

Γι' αυτόν( κυρίως ) το λόγο υπάρχουν τα αρχεία, τα οποία αποθηκεύονται σε σταθερή μνήμη( CD, HDD, κτλ ), για να χρησιμοποιηθούν αργότερα.

Η C παρέχει πολλές συναρτήσεις για είσοδο και έξοδο σε αρχεία, εδώ θα μάθουμε τις βασικές:

FILE * fopen ( const char * filename, const char * mode );
filename: Αλφαριθμητικό που περιέχει το όνομα του αρχείου
mode: Αλφαριθμητικό που λέει πώς πρέπει να ανοιχτεί το αρχείο
επιστρέφει τον δείκτη του ανοιγμένου αρχείου, και NULL αν αποτύχει

οι δυνατές τιμές του "mode" είναι συγκεκριμένες:

"r" Ανοίγει το αρχείο για διάβασμα, αποτυγχάνει αν δεν υπάρχει
"w" Ανοίγει το αρχείο για γράψιμο, αν δεν υπάρχει το δημιουργεί, αν υπάρχει σβήνει να περιεχόμενά του
"a" Ανοίγει το αρχείο για πρόσθεση κειμένου/δεδομένων πάντα στο τέλος του. Αν δεν υπάρχει, το δημιουργεί
"r+" Ανοίγει το αρχείο για διάβασμα και γράψιμο, αποτυγχάνει αν δεν υπάρχει
"w+" Ανοίγει το αρχείο για διάβασμα και γράψιμο, αν δεν υπάρχει το δημιουργεί, αν υπάρχει σβήνει να περιεχόμενά του
"a+" Ανοίγει το αρχείο για διάβασμα από παντού αλλά και πρόσθεση κειμένου/δεδομένων πάντα στο τέλος του. Αν δεν υπάρχει, το δημιουργεί

Αυτά τα modes ανοίγουν αρχεία κειμένου. Αν θέλετε να ανοίξετε δυαδικά/αρχεία δεδομένων, πρέπει να προσθέσετε το γράμμα "b"( πάντα μικρό ) στο τέλος του αλφαριθμητικού mode ή πριν το "+".


Πάντα, αφού τελειώσετε με το ανοιγμένο αρχείο, καλό είναι να το κλείνετε:

int fclose ( FILE * stream );
stream: Δείκτης σε ένα ανοιγμένο αρχείο
επιστρέφει μηδέν αν καταφέρει να κλείσει το αρχείο, αλλιώς επιστρέφει EOF


Για να κάνετε είσοδο και έξοδο σε αρχεία κειμένου, συνήθως χρησιμοποιούνται οι:

int fprintf ( FILE * stream, const char * format, ... );
int fscanf ( FILE * stream, const char * format, ... );
int fputs ( const char * str, FILE * stream ); // Δεν προσθέτει τον χαρακτήρα '\n' στο τέλος, σε αντίθεση με την puts()
char * fgets ( char * str, int num, FILE * stream ); // Δεν πετάει τον χαρακτήρα '\n', σε αντίθεση με την gets()

όπως βλέπετε, η μόνη "διαφορετική" συνάρτηση είναι η "fgets()", επειδή παίρνει και μια παράμετρο που αντιστοιχεί στο μέγεθος του αλφαριθμητικού. Προτιμάται έναντι της "gets()" επειδή δεν υπάρχει πιθανότητα να γίνει κάτι άσχημο αν ο χρήστης δώσει κάτι μεγαλύτερο απ' τη χωρητικότητα του αλφαριθμητικού.

Υπάρχουν βέβαια και άλλες συναρτήσεις, όπως οι "fseek()" και "ftell()", που αλλάζουν και επιστρέφουν αντίστοιχα τη τρέχουσα θέση ανάγνωσης και/ή εγγραφής στο αρχείο. Θα αναφερθώ εκτενώς σε αυτές και άλλες σε επόμενο άρθρο.

Για είσοδο και έξοδο σε δυαδικά αρχεία/αρχεία δεδομένων, χρησιμοποιούνται κυρίως δύο συναρτήσεις:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
ptr: Δείκτης πίνακα όπου τα δεδομένα θα αποθηκευτούν
size: Το μέγεθος μεμονωμένων στοιχείων του πίνακα
count: Το πλήθος των στοιχείων του πίνακα
stream: Δείκτης σε αρχείο ανοιγμένο για δυαδική ανάγνωση
επιστρέφει το πλήθος των στοιχείων που κατάφερε να διαβάσει απ' το αρχείο


size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
ptr: Δείκτης πίνακα απ' όπου τα δεδομένα θα παρθούν
size: Το μέγεθος μεμονωμένων στοιχείων του πίνακα
count: Το πλήθος των στοιχείων του πίνακα
stream: Δείκτης σε αρχείο ανοιγμένο για δυαδική εγγραφή
επιστρέφει το πλήθος των στοιχείων που κατάφερε να γράψει στο αρχείο


να σημειωθεί ότι οι ftell()/fseek() είναι πολύ σημαντικές για δυαδική είσοδο/έξοδο, επειδή συνήθως το μόνο που γνωρίζουμε στα δυαδικά αρχεία με σιγουριά είναι οι "επικεφαλίδες" τους( αν έχουν ), δηλαδή δεδομένα στην αρχή του αρχείου που κρατάνε πληροφορίες για το υπόλοιπο, και σου λένε πού είναι τι.

Στο παρόν άρθρο δεν ασχολούμαστε με τις ιδιαιτερότητες των αρχείων και των διαδρομών τους, επειδή αυτά είναι διαφορετικά για κάθε σύστημα. Όλες οι διαδρομές αρχείων είναι καλό να είναι σε σχέση με την εξ' ορισμού θέση των αρχείων, που συνήθως είναι η θέση του εκτελέσιμου( αλλά όχι πάντα ), αντί για απόλυτες. Πχ "file" αντί για "C:\\myTestCode\\file".

Αυτά τα ολίγα για τώρα. Μη ξεχνάτε πάντα να ελέγχετε αν εκτελέστηκαν σωστά οι συναρτήσεις εισόδου/εξόδου αρχείων, μέσω των επιστροφών τους, επειδή δεν είναι λίγες οι φορές που παρουσιάζονται προβλήματα.