11. Είσοδος/Έξοδος
Σύνοψη Ορίσματα γραμμής εντολών, η συνάρτηση getopt(), αρχεία κειμένου και δυαδικά αρχεία, ο τύπος δεδομένων FILE, ανάγνωση δεδομένων από αρχεία κειμένου με τις fgetc(), fgets(), fscanf(), αποθήκευση δεδομένων σε αρχεία κειμένου με τις fputc(), fprintf(), ανάγνωση δεδομένων από δυαδικά αρχεία με την fread(), εγγραφή δεδομένων σε δυαδικά αρχεία με την fwrite(), μετακίνηση σε δυαδικά αρχεία με την fseek().
Προαπαιτούμενη γνώση Τύποι δεδομένων, είσοδος/έξοδος, δομές επιλογής και επανάληψης, συναρτήσεις, πίνακες, δομές, δείκτες, αλφαριθμητικά.
11.1 Ορίσματα γραμμής εντολών
Η main() είναι ειδικός τύπος συνάρτησης καθώς αποτελεί το σημείο εισόδου (entry point) για την εκτέλεση του προγράμματος. Ο προκαθορισμένος τύπος επιστροφής της είναι int και υπάρχουν δύο τύποι της, ένας που δεν δέχεται παραμέτρους και ένας που δέχεται. Στα παραδείγματα κώδικα των προηγούμενων κεφαλαίων η main() δεν δεχόταν παραμέτρους και για αυτόν το λόγο συμπεριλαμβανόταν στον κώδικα με τη μορφή:
Στη συνέχεια θα παρουσιαστούν παραδείγματα όπου η main() θα δέχεται ορίσματα κατά την κλήση της, τα λεγόμενα ορίσματα γραμμής εντολών (command line arguments).
11.1.1 Παραδείγματα με ορίσματα γραμμής εντολών
Ένα παράδειγμα παρουσιάζεται στον κώδικα 11.1 όπου εντός των παρενθέσεων της main() υπάρχουν δύο παράμετροι:
- Στην πρώτη θέση μια ακέραια παράμετρος με όνομα argc που περιέχει το πλήθος των ορισμάτων που δίνονται από τη γραμμή εντολών κατά την κλήση του προγράμματος. Στο πλήθος αυτό προσμετράται πάντα και το όνομα του εκτελέσιμου προγράμματος.
- Μια παράμετρος με όνομα argv που είναι ένας πίνακας αλφαριθμητικών. Τα στοιχεία του πίνακα είναι τα ορίσματα της γραμμής εντολών συμπεριλαμβανομένου του ονόματος του εκτελέσιμου προγράμματος.
Τα ονόματα των παραμέτρων δεν είναι κατά ανάγκη argc και argv, αλλά έχει καθιερωθεί να χρησιμοποιούνται αυτά. Αν ο κώδικας 11.1 μεταγλωττιστεί και εκτελεστεί όπως στη συνέχεια, τα αποτελέσματα θα είναι:
Κώδικας 11.1: ch11_p1.c - ένα απλό παράδειγμα εμφάνισης του πλήθους των ορισμάτων που δέχεται κατά την εκτέλεσή του ένα πρόγραμμα. | |
---|---|
Το πλήθος των ορισμάτων που εκτυπώνεται είναι 1, διότι όπως αναφέρθηκε προσμετράται και το ίδιο το εκτελέσιμο πρόγραμμα ως πρώτο. Αν στη συνέχεια εκτελέσουμε το ίδιο πρόγραμμα με περισσότερα ορίσματα θα έχουμε την ακόλουθη έξοδο:
Σε αυτήν την περίπτωση τα ορίσματα είναι το όνομα του εκτελέσιμου και τα alfa, bravo, charlie και συνεπώς το πλήθος είναι 4. Ένας νέος κώδικας που εκτυπώνει όλα τα ορίσματα είναι ο κώδικας 11.2 όπου κάθε όρισμα κατά την κλήση του εκτελέσιμου καταλαμβάνει και μια θέση στον πίνακα argv.
Κώδικας 11.2: ch11_p2.c - εμφάνιση των ορισμάτων που δέχεται κατά την εκτέλεσή του το πρόγραμμα. | |
---|---|
Η μεταγλώττιση και εκτέλεση του προγράμματος θα δώσει τα ακόλουθα αποτελέσματα:
$ gcc ch11_p2.c ‐o ch11_p2
$ ./ch11_p2 alfa bravo charlie
argv[0]= ./ch11_p2
argv[1]= alpha
argv[2]= bravo
argv[3]= charlie
Στο επόμενο παράδειγμα, στον κώδικα 11.3, τα ορίσματα της γραμμής εντολών χρησιμοποιούνται για την εκτέλεση αριθμητικών πράξεων. Ο χρήστης εκτελεί το πρόγραμμα εισάγοντας την επιθυμητή πράξη π.χ. ADD για πρόσθεση (SUB, MUL, DIV για αφαίρεση, πολλαπλασιασμό και διαίρεση αντίστοιχα) και τους τελεστέους της πράξης. Ο κώδικας ελέγχει αρχικά ότι ο αριθμός των ορισμάτων είναι σωστός και αν δεν έχουν εισαχθεί τα 3 αναμενόμενα ορίσματα (πράξη, τελεστέος 1, τελεστέος 2) τότε εμφανίζεται μήνυμα που πληροφορεί για τον ορθό τρόπο εκτέλεσης του προγράμματος και η εκτέλεση τερματίζει. Αν από την άλλη μεριά έχει εισαχθεί το σωστό πλήθος ορισμάτων, τότε εκτελείται η πράξη και το αποτέλεσμα εμφανίζεται στην οθόνη. Για τη μετατροπή των ορισμάτων από αλφαριθμητικά σε πραγματικούς αριθμούς χρησιμοποιείται η συνάρτηση atof() που ορίζεται στο stdlib.h.
Ένα παράδειγμα μεταγλώττισης και εκτέλεσης του παραπάνω προγράμματος παρουσιάζεται στη συνέχεια:
11.1.2 Η συνάρτηση getopt()
Για διάφορες εντολές που μπορούν να δοθούν στη γραμμή εντολών υπάρχουν διακόπτες (switches) που τροποποιούν τη συμπεριφορά τους. Για παράδειγμα η εντολή tail σε περιβάλλον UNIX μπορεί να κληθεί με τον διακόπτη ‐n όπως στη συνέχεια:
Το αποτέλεσμα της εντολής θα είναι η εκτύπωση των 3 τελευταίων γραμμών του αρχείου file.txt. Αν η κλήση της tail γινόταν χωρίς τον διακόπτη ‐n και την τιμή 3, τότε θα εμφάνιζε τις τελευταίες 10 γραμμές του αρχείου καθώς αυτή είναι η προκαθορισμένη συμπεριφορά που έχει οριστεί για το συγκεκριμένο μικρό πρόγραμμα. Συνεπώς, για την tail ο διακόπτης ‐n καθορίζει το πλήθος των γραμμών που εμφανίζονται. Παρόμοια λειτουργικότητα μπορεί να επιτευχθεί και σε προγράμματα C με χρήση της συνάρτησης getopt(int argc, char **argv, char *options) που ορίζεται στο unistd.h. Οι παράμετροι που δέχεται η συνάρτηση getopt() χρησιμοποιούνται ως εξής:
- Η argc είναι το πλήθος των ορισμάτων της γραμμής εντολών.
- Η argv είναι ο πίνακας των ορισμάτων της γραμμής εντολών.
- Η options χρησιμοποιείται για να ορίσει ποια ορίσματα της γραμμής εντολών είναι διακόπτες και ποια απαιτούν επιπλέον και τιμή.
Ένα παράδειγμα χρήσης της συνάρτησης getopt() παρουσιάζεται στον κώδικα 11.4, με σχόλια που εξηγούν τον ρόλο της μεταβλητής options, της συνάρτησης getopt() και της μεταβλητής optarg που ορίζεται στο unistd.h.
Η συνάρτηση getopt() πρέπει να καλείται επαναληπτικά μέχρι να επιστρέψει -1. Σε κάθε επανάληψη επιστρέφει το επόμενο όρισμα στη σειρά των ορισμάτων. Τα αποδεκτά ορίσματα περιγράφονται στη μεταβλητή options. Αν μετά το όνομα του ορίσματος ακολουθεί το σύμβολο :, τότε το όρισμα αυτό πρέπει να ακολουθείται από κάποια τιμή. Η λήψη αυτής της τιμής γίνεται μέσω της μεταβλητής optarg. Στην περίπτωση του κώδικα 11.4 επιτρέπονται τα ακόλουθα τρία ορίσματα:
- Το όρισμα ‐a, που είναι ένας απλός διακόπτης και συνεπώς δεν ακολουθείται από κάποια τιμή. Αν η εκτέλεση του προγράμματος συμπεριλάβει το όρισμα αυτό, η μεταβλητή aflag θα λάβει την τιμή 1, αλλιώς θα λάβει την τιμή 0.
- Το όρισμα ‐b, που δέχεται αμέσως μετά μια ακέραια τιμή. Αυτή η τιμή ανατίθεται στην τοπική μεταβλητή bvalue.
- Το όρισμα ‐d, που δέχεται μια δεκαδική τιμή μετά από αυτό. Αυτή η δεκαδική τιμή θα ανατεθεί στην τοπική μεταβλητή dvalue.
Κατάσταση (mode) | Σημασία |
---|---|
"r" | Ανοίγει το αρχείο μόνο για ανάγνωση. Αν το αρχείο δεν υπάρχει, επιστρέφεται σφάλμα. |
"w" | Ανοίγει το αρχείο για εγγραφή. Αν το αρχείο υπάρχει, τα περιεχόμενά του διαγράφονται και αν δεν υπάρχει, δημιουργείται ένα νέο αρχείο. |
"a" | Ανοίγει το αρχείο για προσάρτηση (append). Αν το αρχείο υπάρχει, η εγγραφή γίνεται στο τέλος του αρχείου. Αν δεν υπάρχει, δημιουργείται ένα νέο. |
"r+" | Ανοίγει το αρχείο για ανάγνωση και εγγραφή. Δεν δημιουργεί νέο αρχείο αν αυτό δεν υπάρχει. |
"w+" | Παρόμοιο με το "w", αλλά επιτρέπει και την ανάγνωση του αρχείου. Εάν το αρχείο υπάρχει, τα περιεχόμενά του διαγράφονται. |
"a+" | Παρόμοιο με το "a", αλλά επιτρέπει και την ανάγνωση του αρχείου. Η εγγραφή γίνεται στο τέλος του αρχείου. Δηλαδή, ανεξάρτητα από την τρέχουσα θέση του δείκτη στο αρχείο κατά την ανάγνωση, η εγγραφή προσθέτει πάντα τα δεδομένα στο τέλος του αρχείου. |
Ένα παράδειγμα εκτέλεσης παρουσιάζεται στη συνέχεια:
11.2 Ο τύπος δεδομένων FILE
Υπάρχουν δύο κατηγορίες αρχείων, τα αρχεία κειμένου και τα δυαδικά αρχεία. Τα αρχεία κειμένου περιέχουν δεδομένα που μπορούν να διαβαστούν από οποιονδήποτε κειμενογράφο απλού κειμένου. Σε αυτήν την κατηγορία ανήκουν για παράδειγμα τα αρχεία κώδικα. Στη δεύτερη κατηγορία είναι αρχεία που απαιτούν ειδική εφαρμογή έτσι ώστε να διαβαστούν τα περιεχόμενά τους. Τέτοια αρχεία είναι για παράδειγμα τα αρχεία .docx από το Microsoft Word, τα αρχεία .xlsx από το Microsoft Excel, τα αρχεία εικόνας .png κ.λπ.
Στη γλώσσα C τα αρχεία ανοίγουν με τη συνάρτηση fopen(filepath, mode). Το πρώτο όρισμα είναι το όνομα του αρχείου που πρέπει να ανοίξει (συμπληρωμένο με τη διαδρομή του στο σύστημα αρχείων, αν το αρχείο δεν βρίσκεται στον ίδιο κατάλογο με το αρχείο του κώδικα). Το δεύτερο όρισμα ορίζει την κατάσταση (mode) στην οποία θα ανοίξει το αρχείο με αποδεκτές τιμές αυτές που παρουσιάζονται στον Πίνακα 11.1. Η συνάρτηση fopen() επιστρέφει NULL αν δεν μπορεί να ανοίξει το συγκεκριμένο αρχείο με το συγκεκριμένο mode. Αν τα καταφέρει επιστρέφει έναν δείκτη προς μια ειδική δομή FILE.
Το παράδειγμα του κώδικα 11.5 επιχειρεί να ανοίξει το αρχείο test.txt για ανάγνωση υποθέτοντας ότι βρίσκεται στον ίδιο τοπικό φάκελο. Αν το αρχείο ανοίξει επιτυχώς, τότε εμφανίζεται ένα μήνυμα που πληροφορεί για την επιτυχία ανοίγματος του αρχείου αλλιώς εμφανίζεται μήνυμα λάθους.
Κώδικας 11.5: ch11_p5.c - άνοιγμα αρχείου κειμένου. | |
---|---|
11.3 Είσοδος από αρχεία κειμένου
11.3.1 Ανάγνωση χωρίς διαμόρφωση
Για την ανάγνωση αρχείων απλού κειμένου υπάρχουν δύο τρόποι: ο πρώτος είναι να γίνει ανάγνωση του αρχείου χαρακτήρα προς χαρακτήρα, ενώ ο δεύτερος είναι να γίνει ανάγνωση ανά γραμμή. Ο πρώτος τρόπος παρουσιάζεται στον κώδικα 11.6, όπου γίνεται ανάγνωση όλων των χαρακτήρων που βρίσκονται σε ένα αρχείο και εμφανίζεται ο συνολικός αριθμός τους καθώς και ο συνολικός αριθμός γραμμών. Για την ανάγνωση κάθε χαρακτήρα χρησιμοποιείται η συνάρτηση fgetc() που κάθε κλήση της επιστρέφει τον επόμενο χαρακτήρα από το αρχείο εισόδου και αν δεν υπάρχουν άλλοι χαρακτήρες, επιστρέφει τη σταθερά EOF (End Of File).
Ο τρόπος ανάγνωσης αρχείου του κώδικα 11.6 είναι σχετικά αργός καθώς πρέπει να κάνει τόσες αναγνώσεις από το αρχείο όσοι είναι και οι χαρακτήρες του αρχείου. Εναλλακτικά, μπορεί να γίνει ανάγνωση γραμμή προς γραμμή με τη συνάρτηση fgets() όπως παρουσιάζεται στον κώδικα 11.7.
Η συνάρτηση fgets() δέχεται τρία ορίσματα:
- Έναν δείκτη προς το αλφαριθμητικό στο οποίο θα γίνει αποθήκευση της εισόδου.
- Τον μέγιστο αριθμό χαρακτήρων που θα διαβαστούν από το αρχείο. Αν η ανάγνωση φτάσει στο τέλος της γραμμής και το πλήθος των γραμμάτων είναι μικρότερο από τον μέγιστο αριθμό, τότε η fgets() τερματίζει και επιστρέφει τη γραμμή που διάβασε, διαφορετικά διαβάζει τόσους χαρακτήρες όσος είναι ο μέγιστος αριθμός χαρακτήρων.
- Ένα δείκτη προς το αρχείο από το οποίο γίνεται η ανάγνωση.
Επίσης, η συνάρτηση fgets() επιστρέφει έναν δείκτη προς τη γραμμή που διάβασε από το αρχείο. Αν τα δεδομένα του αρχείου τελειώσουν, τότε η συνάρτηση επιστρέφει NULL.
Έστω ένα αρχείο test.txt, στον ίδιο κατάλογο με τον κώδικα, με το ακόλουθο περιεχόμενο:
Excerpt from the Tao of programming (https://www.mit.edu/~xela/tao.html)
If the Tao is great, then the operating system is great.
If the operating system is great, then the compiler is great.
If the compiler is great, then the application is great.
The user is pleased , and there is harmony in the world.
Η εκτέλεση του κώδικα 11.6, όπως και του κώδικα 11.7 για το συγκεκριμένο αρχείο (test.txt) εμφανίζει τα ακόλουθα αποτελέσματα:
Excerpt from the Tao of programming (https://www.mit.edu/~xela/tao.html)
If the Tao is great, then the operating system is great.
If the operating system is great, then the compiler is great.
If the compiler is great, then the application is great.
The user is pleased , and there is harmony in the world.
Characters: 304
Lines: 5
Αξίζει να σημειωθεί ότι η fgets() διαβάζοντας το αρχείο κειμένου αντιγράφει στο αλφαριθμητικό και την αλλαγή γραμμής. Οι γραμμές 16-21 στον κώδικα 11.7 αντικαθιστούν τον τελευταίο χαρακτήρα, αν είναι αλλαγή γραμμής, με τον χαρακτήρα τερματισμού αλφαριθμητικών.
11.3.2 Ανάγνωση με διαμόρφωση
Αν τα δεδομένα που πρέπει να διαβαστούν δεν είναι κείμενο, αλλά είναι για παράδειγμα αριθμοί, τότε η ανάγνωση των τιμών από το αρχείο μπορεί να γίνει με τη χρήση της fscanf(). Στο παράδειγμα του κώδικα 11.8, έστω ότι στο αρχείο grades.txt υπάρχουν σε κάθε γραμμή του τρεις αριθμοί, ένας ακέραιος που είναι ο αριθμός μητρώου φοιτητή και δύο δεκαδικοί που είναι η βαθμολογία του φοιτητή σε διάλεξη και εργαστήριο αντίστοιχα. Το πρόγραμμα εμφανίζει τον αριθμό μητρώου του φοιτητή με τη μεγαλύτερη μέση βαθμολογία. Ο κώδικας θεωρεί ότι το πλήθος των φοιτητών είναι γνωστό και ίσο με 5.
Αν θεωρηθεί ότι τα περιεχόμενα του αρχείου εισόδου (grades.txt) είναι τα ακόλουθα:
τότε το αποτέλεσμα εκτέλεσης του κώδικα 11.8 θα είναι:
Ωστόσο, συνήθως το πλήθος των εγγραφών σε ένα αρχείο δεν είναι γνωστό και επομένως θα πρέπει να χρησιμοποιηθεί διαφορετικός τρόπος για την ανάγνωση όλων των στοιχείων αρχείου δεδομένων. Για να επιτευχθεί αυτό μπορεί να χρησιμοποιηθεί η τιμή επιστροφής της συνάρτησης fscanf() καθώς επιστρέφει το πλήθος των ορισμάτων που μπόρεσε να διαβάσει με επιτυχία. Για παράδειγμα η ανάθεση:
θα επιστρέψει στη μεταβλητή n την τιμή 2 αν μπόρεσε να διαβάσει με επιτυχία δύο αριθμούς. Αν δεν υπάρχουν όμως άλλοι αριθμοί να διαβάσει, τότε η συνάρτηση θα επιστρέψει την τιμή 0. Το χαρακτηριστικό αυτό χρησιμοποιείται στον κώδικα 11.9, προκειμένου να εντοπιστεί και πάλι η καλύτερη βαθμολογία φοιτητή.
Πολλές φορές τα αρχεία δεδομένων ενδέχεται να χρησιμοποιούν διαχωριστές για τα δεδομένα. Επίσης, εφαρμογές όπως το Microsoft Excel ή το Libreoffice Calc εξάγουν τα δεδομένα σε μορφή CSV (Comma Separated Values), δηλαδή κάθε στήλη χωρίζεται από την επόμενη με κάποιον διαχωριστή όπως είναι το κόμμα. Έτσι το προηγούμενο αρχείο βαθμολογίας θα μπορούσε να έχει την εξής διαμόρφωση:
Για να μπορέσει η εφαρμογή να διαβάσει αρχεία αυτής της μορφής, θα πρέπει να γίνει ανάγνωση καθεμιάς γραμμής του αρχείου ξεχωριστά και στη συνέχεια να διαχωριστεί η γραμμή στα επιμέρους στοιχεία της, δηλαδή κωδικό σπουδαστή και βαθμολογίες. Ο κώδικας 11.10 πραγματοποιεί ακριβώς αυτό, ενώ για τον διαχωρισμό των στοιχείων της κάθε γραμμής χρησιμοποιείται η συνάρτηση strtok().
11.4 Έξοδος σε αρχεία κειμένου
Για την εγγραφή χαρακτήρων σε αρχεία κειμένου μπορεί να χρησιμοποιηθεί η συνάρτηση fputc(). Η συνάρτηση αυτή δέχεται ως πρώτο όρισμα τον χαρακτήρα που θα γραφεί στο αρχείο και ως δεύτερο όρισμα έναν δείκτη προς το αρχείο που θα γίνει η εγγραφή. Στο παράδειγμα του κώδικα 11.11, παρουσιάζεται η εγγραφή τυχαίων γραμμάτων του αγγλικού αλφαβήτου σε ένα αρχείο κειμένου. Ο χρήστης εισάγει το επιθυμητό όνομα αρχείου και το πλήθος των τυχαίων γραμμάτων και παράγονται αντίστοιχα κεφαλαία γράμματα που γράφονται σε αυτό το αρχείο.
Ένα παράδειγμα εκτέλεσης παρουσιάζεται στη συνέχεια:
Για την εγγραφή άλλων τιμών πέρα από χαρακτήρες σε αρχεία μπορεί να χρησιμοποιηθεί η συνάρτηση fprintf() που έχει παρόμοια σύνταξη με τη συνάρτηση printf() αλλά με τη διαφορά πως η έξοδος γίνεται σε αρχείο, αντί για την οθόνη. Στο παράδειγμα του κώδικα 11.12 αποθηκεύονται στο αρχείο fibonacci.txt οι 10 πρώτοι όροι της ακολουθίας Fibonacci (1).
Μετά την εκτέλεση του προγράμματος θα έχει δημιουργηθεί το αρχείο fibonacci.txt στον ίδιο κατάλογο με το εκτελέσιμο πρόγραμμα και θα έχει τα ακόλουθα περιεχόμενα:
Τα πεδία δομών μπορούν επίσης να εγγραφούν σε αρχεία κειμένου. Για παράδειγμα ο κώδικας 11.13, αποθηκεύει δύο εγγραφές της δομής student στο αρχείο students.txt.
Στο αρχείο students.txt η πληροφορία εγγράφεται με την ακόλουθη μορφή:
11.5 Δυαδικά αρχεία
Τα αρχεία κειμένου, αν και είναι εύκολα στον χειρισμό τους και άμεσα αναγνώσιμα, αποτελούν τη συντριπτική μειοψηφία των αρχείων που υπάρχουν σε έναν ηλεκτρονικό υπολογιστή. Για παράδειγμα τα αρχεία ήχου, τα αρχεία εικόνας, τα φύλλα εργασίας, οι παρουσιάσεις κ.λπ. δεν είναι αρχεία κειμένου αλλά ειδικού τύπου αρχεία που συχνά αποκαλούνται δυαδικά αρχεία (binary files). Αρχεία τέτοιου είδους απαιτούν ειδικές εφαρμογές για τον χειρισμό τους, αλλά η πρόσβαση στα δεδομένα τους είναι πολύ πιο γρήγορη από ότι σε αρχεία κειμένου. Αυτό συμβαίνει διότι τα δεδομένα γράφονται και διαβάζονται στο αρχείο απευθείας ως bytes και όχι με διαμόρφωση κειμένου. Στη C συνήθως τα δυαδικά αρχεία χρησιμοποιούνται για εγγραφή και ανάγνωση δομών (structs).
11.5.1 Έξοδος σε δυαδικό αρχείο
Η εγγραφή δεδομένων σε δυαδικά αρχεία δεν γίνεται με τη συνάρτηση fprint(), καθώς αυτή γράφει μορφοποιημένο κείμενο και όχι απευθείας bytes. Η εγγραφή δυαδικών δεδομένων γίνεται με τη χρήση της συνάρτησης fwrite(x, size, count, fp) με τα ορίσματά της να έχουν την ακόλουθη σημασία:
- x είναι ένας δείκτης προς τα δεδομένα που πρόκειται να εγγραφούν στο αρχείο. Συνήθως πρόκειται για έναν δείκτη προς μια δομή ή για έναν πίνακα δομών.
- size είναι το μέγεθος σε bytes καθεμίας εγγραφής που θα αποθηκευτεί στο αρχείο.
- count είναι το πλήθος των εγγραφών που θα αποθηκευτούν στο αρχείο.
- fp είναι δείκτης προς το αρχείο.
Στο παράδειγμα του κώδικα 11.14 παρουσιάζεται η αποθήκευση δυο εγγραφών της δομής person στο αρχείο persons.txt.
Η εμφάνιση των περιεχομένων του αρχείου persons.bin δεν είναι εφικτή με έναν απλό επεξεργαστή κειμένου (αν και οι χαρακτήρες στα δεδομένα μπορεί να είναι ορατοί). Ωστόσο, αν χρησιμοποιηθεί μια εντολή όπως η xxd (1) ενός UNIX συστήματος θα ληφθούν αποτελέσματα παρόμοια με τα ακόλουθα:
$ xxd persons.bin
00000000: 4a6f 686e 0000 0000 0000 0000 0000 0000 John............
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 446f 6500 0000 0000 0000 0000 ....Doe.........
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 2e00 0000 5269 6368 ............Rich
000000d0: 6172 6400 0000 0000 0000 0000 0000 0000 ard.............
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000130: 526f 6500 0000 0000 0000 0000 0000 0000 Roe.............
00000140: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000190: 0000 0000 2100 0000 ....!...
Ο κώδικας 11.14 γράφει στο αρχείο persons.bin με δύο εντολές fwrite, αλλά αυτό θα μπορούσε να συμβεί και με μόνο μία εντολή για μεγαλύτερη ταχύτητα, όπως φαίνεται στον κώδικα 11.15.
11.5.2 Είσοδος από δυαδικό αρχείο
Η συνάρτηση fread() μπορεί να χρησιμοποιηθεί για ανάγνωση δεδομένων από δυαδικά αρχεία και η σύνταξή της είναι παρόμοια με τη σύνταξη της fwrite(). Στο παράδειγμα του κώδικα 11.16 γίνεται ανάγνωση των δύο εγγραφών της δομής person που αποθηκεύτηκαν στο αρχείο persons.bin με τον κώδικα 11.15.
11.5.3 Μετακίνηση με την fseek()
Μια ευκολία που παρέχουν τα δυαδικά αρχεία είναι η δυνατότητα μετακίνησης σε οποιοδήποτε σημείο τους.
Για να γίνει αυτό χρησιμοποιείται η συνάρτηση:
- fp είναι ο δείκτης προς το αρχείο.
- offset είναι ο αριθμός των bytes σε σχέση με το whence.
-
whence μπορεί να λάβει τρεις συμβολικές τιμές:
- SEEK_SET, συμβολίζει την αρχή του αρχείου.
- SEEK_CUR, συμβολίζει την τρέχουσα θέση στο αρχείο.
- SEEK_END, συμβολίζει το τέλος του αρχείου
Μια συνηθισμένη χρήση της fseek() είναι για τον υπολογισμό του συνολικού μεγέθους ενός αρχείου σε bytes. Αυτό μπορεί να γίνει σε συνδυασμό με τη συνάρτηση ftell(), που επιστρέφει την τρέχουσα θέση σε bytes σε ένα αρχείο. Ένα παράδειγμα υπολογισμού του μεγέθους ενός αρχείου παρουσιάζεται στον κώδικα 11.17 όπου γίνεται μετακίνηση στο τέλος του αρχείου και στη συνέχεια υπολογίζεται το συνολικό μέγεθος σε bytes με χρήση της ftell().
Κώδικας 11.17: ch11_p17.c - υπολογισμός του μεγέθους ενός αρχείου σε bytes με τις fseek() και ftell(). | |
---|---|
Θεωρώντας ότι το αρχείο persons.bin που δημιουργήθηκε με τον κώδικα 11.15 υπάρχει, η εκτέλεση του παραπάνω προγράμματος θα εμφανίσει:
Ένα ακόμα παράδειγμα χρήσης της fseek() παρουσιάζεται στον κώδικα 11.18. Ο κώδικας ανοίγει το δυαδικό αρχείο εγγραφών persons.bin, μετακινείται στην τελευταία εγγραφή, διαβάζει τα περιεχόμενά της και τα εμφανίζει.
Η εκτέλεση του προγράμματος, εφόσον υπάρχει το αρχείο persons.bin θα εμφανίσει:
11.6 Ασκήσεις
Άσκηση 1
Να γραφεί πρόγραμμα που ο χρήστης να εισάγει το όνομα ενός αρχείου κειμένου και το πρόγραμμα να εμφανίζει το ποσοστό των χαρακτήρων του αρχείου που είναι κεφαλαία γράμματα του αγγλικού αλφαβήτου.
Λύση άσκησης 1
Άσκηση 2
Nα γραφεί πρόγραμμα που ο χρήστης να εισάγει το όνομα ενός αρχείου κειμένου και το πρόγραμμα να εμφανίζει τις γραμμές του αρχείου που ξεκινούν με κεφαλαίο γράμμα του αγγλικού αλφαβήτου.
Λύση άσκησης 2
Άσκηση 3
Nα γραφεί πρόγραμμα που ο χρήστης να εισάγει ακέραιους αριθμούς επαναληπτικά μέχρι να δώσει την τιμή 0. Για κάθε αριθμό που εισάγει ο χρήστης, αν είναι πρώτος, να εισάγεται στο αρχείο primes.txt και να εμφανίζεται σχετικό μήνυμα. Το πρόγραμμα πριν τον τερματισμό του να εμφανίζει τα περιεχόμενα του primes.txt.
Λύση άσκησης 3
Άσκηση 4
Γράψτε ένα πρόγραμμα που θα εγγράφει μια ακολουθία ακεραίων τιμών σε ένα αρχείο κειμένου με τις τιμές μεταξύ τους διαχωρισμένες με κόμματα. Οι τιμές να επιλέγονται τυχαία στο διάστημα [0,100) και το πλήθος τους να καθορίζεται από τον χρήστη κατά την εκτέλεση του προγράμματος. Στη συνέχεια να διαβάζει τις τιμές από το αρχείο και να υπολογίζει και να εμφανίζει τον μέσο όρο τους. Να υπολογίζει και να εμφανίζει τους χρόνους που χρειάστηκε για να γίνει τόσο η εγγραφή των ακεραίων τιμών στο αρχείο, όσο και η ανάγνωση των τιμών. Επαναλάβετε τη διαδικασία, αλλά αυτήν τη φορά για εγγραφή και ανάγνωση των ακεραίων τιμών σε δυαδικό αρχείο. Συγκρίνετε τους χρόνους.
Παρατήρηση: Η μέτρηση χρόνου εκτέλεσης από τη γραμμή εντολών μπορεί να γίνει με το βοηθητικό πρόγραμμα time σε Linux και MacOS. Στα Windows μπορεί να εγκατασταθεί το ptime https://www.pc-tools.net/win32/ptime/ για να προσομοιωθεί παρόμοια λειτουργικότητα με το time του Linux.