📚 Περιεχόμενα Μαθήματος
9.1 Σύνοψη Μαθήματος 8
Στο προηγούμενο μάθημα μάθαμε ότι τα αρχεία μας επιτρέπουν να αποθηκεύουμε δεδομένα μόνιμα στον σκληρό δίσκο. Ας θυμηθούμε τα βασικά:
άνοιγμα
ανάγνωση
κλείσιμο
📋 Τι ξέρουμε μέχρι τώρα
fopen() → ανοίγεις ένα αρχείο 👉 Σαν να ανοίγεις ένα τετράδιο
- "r" = μόνο διάβασμα (δεν γράφεις)
- "w" = γράφεις από την αρχή (σβήνει ό,τι είχε)
- "a" = προσθέτεις στο τέλος
fprintf() → γράφεις μέσα στο αρχείο 👉 Σαν να γράφεις προτάσεις στο τετράδιο (όπως printf, αλλά αντί για οθόνη → πάει στο αρχείο)
fgets() → διαβάζεις μια γραμμή από το αρχείο 👉 Σαν να διαβάζεις μία σειρά από το τετράδιο κάθε φορά
fclose() → κλείνεις το αρχείο 👉 Σαν να κλείνεις το τετράδιο (σημαντικό για να σωθούν σωστά τα δεδομένα)
📖 "r" → ΔΙΑΒΑΣΜΑ μόνο
👉 Δεν γράφεις τίποτα, απλά διαβάζεις
Παράδειγμα:
📌 Σημαίνει:
Άνοιξε το αρχείο για να το διαβάσω
✍️ "w" → ΓΡΑΨΙΜΟ από την αρχή
👉 Σβήνει ό,τι υπήρχε και γράφει από το μηδέν
Παράδειγμα:
📌 Σημαίνει:
Το αρχείο γίνεται ΚΕΝΟ και μετά γράφω "Hello"
➕ "a" → ΠΡΟΣΘΗΚΗ στο τέλος
👉 Δεν σβήνει τίποτα, απλά προσθέτει
Παράδειγμα:
📌 Σημαίνει:
Ό,τι υπάρχει μένει όπως είναι και προσθέτω "Hello" στο τέλος
Σε αυτό το μάθημα θα γνωρίσουμε νέες συναρτήσεις που μας δίνουν περισσότερες δυνατότητες:
- fscanf() — διαβάζει μορφοποιημένα δεδομένα
- fputc() / fgetc() — γράφει/διαβάζει έναν χαρακτήρα
- fputs() — γράφει μια γραμμή
- EOF — πώς καταλαβαίνουμε ότι τελείωσε το αρχείο
9.2 Modes "r+", "w+", "a+"
Εκτός από τα βασικά modes "r", "w", "a", υπάρχουν και οι εκδοχές με + που επιτρέπουν διάβασμα ΚΑΙ γράψιμο στο ίδιο αρχείο.
"r+" → Διάβασμα ΚΑΙ γράψιμο
👉 Δεν σβήνει το αρχείο
📌 Σημαίνει:
Μπορώ να διαβάζω ΚΑΙ να γράφω μέσα στο ίδιο αρχείο (αλλά το αρχείο πρέπει να υπάρχει ήδη)
✍️ "w+" → Διάβασμα ΚΑΙ γράψιμο (από την αρχή)
👉 Σβήνει τα πάντα
📌 Σημαίνει:
Καθαρίζει το αρχείο και μετά μπορώ να γράψω και να διαβάσω
➕ "a+" → Διάβασμα ΚΑΙ προσθήκη στο τέλος
👉 Δεν σβήνει τίποτα
📌 Σημαίνει:
Διαβάζω ό,τι υπάρχει και ό,τι γράφω πάει στο τέλος
9.2.1 📘 Πρακτικό Παράδειγμα — Χρήση "r+"
Πάμε να το δούμε σαν "ζωντανή εκτέλεση" βήμα–βήμα 👍
📁 Δείγμα αρχείου data.txt πριν τρέξει το πρόγραμμα
HELLO WORLD C PROGRAMMING STUDY FILES
▶️ Τι κάνει το πρόγραμμα
1) Άνοιγμα αρχείου (r+)
👉 Το αρχείο ανοίγει ΧΩΡΙΣ να σβηστεί τίποτα
👉 Ο "δείκτης" είναι στην αρχή του αρχείου
2) fgets
👉 Διαβάζει την 1η γραμμή
Άρα:
μπαίνει μέσα στο line
Μετά το fgets(line, 100, f); γίνεται έτσι:
3) printf
🖨️ Έξοδος στην οθόνη:
Πώς το κάνει το printf("%s", line);
Το %s λέει στη C:
"Ξεκίνα από τον πρώτο χαρακτήρα και συνέχισε μέχρι να βρεις '\0'"
👉 Άρα η ίδια η printf έχει μέσα της έναν μηχανισμό που κάνει κάτι σαν loop.
🧠 Δηλαδή είναι ισοδύναμο με:
4) fprintf
⚠️ ΣΗΜΑΝΤΙΚΟ (το κλειδί της άσκησης)
Μετά το fgets, ο δείκτης του αρχείου έχει πάει μετά την πρώτη γραμμή:
HELLO WORLD\n ← εδώ σταματά C PROGRAMMING STUDY FILES
👉 Άρα το fprintf ΔΕΝ γράφει στο τέλος του αρχείου
👉 Γράφει εκεί που βρίσκεται ο δείκτης (μετά το "HELLO WORLD")
📁 Τελικό περιεχόμενο αρχείου μετά την εκτέλεση
HELLO WORLD NEO KEIMENO C PROGRAMMING STUDY FILES
🧠 Τι πρέπει να καταλάβεις (πολύ σημαντικό)
✔️ fgets → μετακινεί τον δείκτη στο τέλος της γραμμής
✔️ fprintf → γράφει από εκεί που είναι ο δείκτης
✔️ r+ → δεν σβήνει τίποτα
🎯 Σύνοψη σαν εικόνα
Πριν:
[HELLO WORLD] ← διαβάζεται C PROGRAMMING STUDY FILES
Μετά το fgets:
HELLO WORLD\n[HERE ↓] C PROGRAMMING STUDY FILES
Μετά το fprintf:
HELLO WORLD NEO KEIMENO C PROGRAMMING STUDY FILES
📘 Ανάγνωση και Δεύτερης Γραμμής
9.2.2 📘 Πρακτικό Παράδειγμα — Χρήση "w+"
Παράδειγμα "w+" με σχόλια
📁 ΤΙ ΥΠΑΡΧΕΙ ΣΤΟ ΑΡΧΕΙΟ (μετά το w+)
HELLO WORLD C PROGRAMMING
🧠 ΤΙ ΣΥΜΒΑΙΝΕΙ ΒΗΜΑ-ΒΗΜΑ
1️⃣ w+
👉 σβήνει ΟΛΟ το αρχείο
(ό,τι υπήρχε πριν → εξαφανίζεται 💥)
2️⃣ fprintf
👉 γράφει καινούριο περιεχόμενο:
3️⃣ rewind(f)
👉 γυρνάει τον δείκτη στην αρχή
4️⃣ fgets
👉 διαβάζει γραμμή-γραμμή όπως πριν
9.2.3 📘 Πρακτικό Παράδειγμα — Χρήση "a+"
Παράδειγμα με "a+"
📁 ΤΙ ΥΠΑΡΧΕΙ ΣΤΟ ΑΡΧΕΙΟ
👉 Αν το αρχείο ΞΕΚΙΝΑ άδειο:
HELLO WORLD C PROGRAMMING
👉 Αν το αρχείο είχε ήδη:
OLD LINE 1 OLD LINE 2
👉 Μετά το "a+" θα γίνει:
OLD LINE 1 OLD LINE 2 HELLO WORLD C PROGRAMMING
🧠 ΤΙ ΣΥΜΒΑΙΝΕΙ
🔹 "a+" σημαίνει:
- ✔ δεν σβήνει τίποτα
- ✔ προσθέτει πάντα στο τέλος
- ✔ μπορείς να διαβάσεις
- ❗ αλλά όταν γράφεις → ΠΑΝΤΑ στο τέλος
⚠️ ΠΟΛΥ ΣΗΜΑΝΤΙΚΟ
Με "a+":
👉 ακόμα κι αν κάνεις fgets,
👉 όταν κάνεις fprintf, γράφει ΠΑΝΤΑ στο τέλος
9.2.4 🔍 Σύγκριση Modes — r/r+, w/w+, a/a+
🔴 1. r vs r+
📌 r → μόνο διάβασμα
- ✔ διαβάζεις
- ❌ δεν γράφεις
- ❌ δεν σβήνει τίποτα
- ❌ πρέπει να υπάρχει αρχείο
📌 r+ → διάβασμα + γράψιμο
- ✔ διαβάζεις
- ✔ γράφεις
- ❌ δεν σβήνει τίποτα
- ❌ πρέπει να υπάρχει αρχείο
⚡ Σύγκριση r / r+
| mode | read | write | delete file | file must exist |
|---|---|---|---|---|
| r | ✔ | ❌ | ❌ | ✔ |
| r+ | ✔ | ✔ | ❌ | ✔ |
🟡 2. w vs w+
📌 w → μόνο γράψιμο
- ✔ γράφεις
- ❌ δεν διαβάζεις
- 💥 σβήνει όλο το αρχείο
- ✔ δημιουργεί νέο αρχείο
📌 w+ → γράψιμο + διάβασμα
- ✔ γράφεις
- ✔ διαβάζεις
- 💥 σβήνει όλο το αρχείο
- ✔ δημιουργεί νέο αρχείο
⚡ Σύγκριση w / w+
| mode | read | write | delete file | create file |
|---|---|---|---|---|
| w | ❌ | ✔ | ✔ | ✔ |
| w+ | ✔ | ✔ | ✔ | ✔ |
🟢 3. a vs a+
📌 a → μόνο προσθήκη
- ✔ γράφεις
- ❌ δεν διαβάζεις
- ❌ δεν σβήνει τίποτα
- ➕ γράφει ΠΑΝΤΑ στο τέλος
- ✔ δημιουργεί αν δεν υπάρχει
📌 a+ → προσθήκη + διάβασμα
- ✔ γράφεις
- ✔ διαβάζεις
- ❌ δεν σβήνει τίποτα
- ➕ γράφει ΠΑΝΤΑ στο τέλος
⚡ Σύγκριση a / a+
| mode | read | write | delete file | where writes |
|---|---|---|---|---|
| a | ❌ | ✔ | ❌ | τέλος |
| a+ | ✔ | ✔ | ❌ | τέλος |
🧠 🔥 ΠΟΛΥ ΑΠΛΟ ΜΝΗΜΟΝΙΚΟ
📌 r / w / a
- r → μόνο διάβασμα
- w → νέο αρχείο
- a → προσθήκη
📌 + σημαίνει:
👉 "μπορώ ΚΑΙ να διαβάζω"
🎯 ΤΕΛΙΚΟ ΣΧΗΜΑ ΣΤΟ ΜΥΑΛΟ
| mode | ιδέα |
|---|---|
| r | βλέπω αρχείο |
| r+ | βλέπω + το αλλάζω |
| w | το ξαναγράφω από την αρχή |
| w+ | το ξαναγράφω + το διαβάζω |
| a | προσθέτω στο τέλος |
| a+ | προσθέτω + μπορώ να διαβάζω |
9.3 fscanf() — Ανάγνωση Μορφοποιημένων Δεδομένων
Η fscanf() δουλεύει ακριβώς όπως η scanf() που ήδη ξέρεις — η μόνη διαφορά είναι ότι διαβάζει από αρχείο αντί για το πληκτρολόγιο.
📝 Σύνταξη
💡 Σύγκριση με scanf
| scanf (πληκτρολόγιο) | fscanf (αρχείο) |
|---|---|
| scanf("%d", &age); | fscanf(fp, "%d", &age); |
| scanf("%s", name); | fscanf(fp, "%s", name); |
Ο κανόνας είναι απλός: αν ξέρεις scanf, ξέρεις και fscanf — απλά βάζεις τον fp ως πρώτη παράμετρο.
📘 Παράδειγμα — Ανάγνωση αριθμού από αρχείο
Ας υποθέσουμε ότι έχουμε ένα αρχείο age.txt που περιέχει:
25
Ο κώδικας για να διαβάσουμε αυτόν τον αριθμό:
📘 Παράδειγμα — Ανάγνωση ονόματος και βαθμού
Αρχείο student.txt:
Giorgos 8.5
⚠️ Προσοχή
Θυμήσου: για int και float βάζουμε & (διεύθυνση), αλλά για string (πίνακα χαρακτήρων) ΟΧΙ. Το όνομα του πίνακα είναι ήδη διεύθυνση!
9.4 fputc() και fgetc() — Χαρακτήρας-Χαρακτήρας
Μερικές φορές θέλουμε να δουλέψουμε με αρχεία έναν χαρακτήρα τη φορά. Γι' αυτό έχουμε δύο απλές συναρτήσεις:
| Συνάρτηση | Τι κάνει |
|---|---|
| fputc(c, fp) | Γράφει έναν χαρακτήρα c στο αρχείο |
| fgetc(fp) | Διαβάζει έναν χαρακτήρα από το αρχείο |
📘 Παράδειγμα — Γραφή χαρακτήρων με fputc()
Μετά την εκτέλεση, το αρχείο hello.txt περιέχει:
Hi!
📘 Παράδειγμα — Ανάγνωση ολόκληρου αρχείου με fgetc()
Το πιο κλασικό μοτίβο: διαβάζουμε όλο το αρχείο χαρακτήρα-χαρακτήρα και το εμφανίζουμε στην οθόνη.
💡 Πώς λειτουργεί το while;
Σε κάθε επανάληψη:
- Η fgetc(fp) διαβάζει έναν χαρακτήρα
- Τον αποθηκεύει στη μεταβλητή c
- Αν ο χαρακτήρας δεν είναι EOF, εκτελείται το σώμα του βρόχου
- Όταν φτάσει στο τέλος, η fgetc επιστρέφει EOF και ο βρόχος σταματάει
9.5 fputs() — Γραφή Ολόκληρης Γραμμής
Η fputs() είναι η απλούστερη συνάρτηση για να γράψουμε ένα string σε αρχείο. Είναι πιο απλή από την fprintf() γιατί δεν έχει format specifiers — απλά γράφει το string όπως είναι.
📝 Σύνταξη
💡 Διαφορά από fprintf()
- fprintf(fp, "Hello\n"); — ίδιο αποτέλεσμα, αλλά πιο "βαριά" συνάρτηση
- fputs("Hello\n", fp); — απλή, γρήγορη, για απλά strings
Προσοχή: Καμία από τις δύο συναρτήσεις δεν προσθέτει αυτόματα \n. Αν θες νέα γραμμή, πρέπει να τη γράψεις εσύ μέσα στο string (όπως στα παραδείγματα παραπάνω).
📘 Παράδειγμα — Γραφή λίστας φρούτων
Το αρχείο fruits.txt θα έχει:
Apple Banana Orange
🔄 Ζεύγη εγγραφής/ανάγνωσης
Για κάθε συνάρτηση εγγραφής έχουμε μια αντίστοιχη για ανάγνωση:
| Τι γράφουμε | Εγγραφή (write) | Ανάγνωση (read) |
|---|---|---|
| Έναν χαρακτήρα | fputc() | fgetc() |
| Μια γραμμή / string | fputs() | fgets() |
| Μορφοποιημένα δεδομένα | fprintf() | fscanf() |
9.6 Τέλος Αρχείου — EOF
Το EOF (End Of File) είναι μια ειδική τιμή που σημαίνει «έφτασα στο τέλος του αρχείου». Είναι ορισμένη στη βιβλιοθήκη <stdio.h> και έχει την τιμή -1.
💡 Αναλογία
Σκέψου ένα βιβλίο: όταν γυρίζεις σελίδες και φτάσεις στο τέλος, βλέπεις τη λέξη «ΤΕΛΟΣ». Το EOF είναι το ίδιο πράγμα για τα αρχεία — ο τρόπος της C να μας πει «δεν υπάρχουν άλλα δεδομένα».
🔍 Πώς ελέγχουμε για EOF;
Πολλές συναρτήσεις επιστρέφουν EOF όταν φτάσουν στο τέλος του αρχείου:
- fgetc() → επιστρέφει EOF
- fscanf() → επιστρέφει EOF (ή αριθμό επιτυχών αναγνώσεων)
- fgets() → επιστρέφει NULL
📘 Παράδειγμα — Μέτρηση χαρακτήρων σε αρχείο
Ας μετρήσουμε πόσους χαρακτήρες έχει ένα αρχείο χρησιμοποιώντας fgetc() και EOF.
Μετράει και τους χαρακτήρες \n (νέα γραμμή) που είναι κι αυτοί κανονικοί χαρακτήρες μέσα στο αρχείο.
📘 Παράδειγμα — Μέτρηση γραμμών
Μια μικρή παραλλαγή: αντί για χαρακτήρες, μετράμε γραμμές. Μια γραμμή τελειώνει όταν συναντήσουμε \n.
9.7 Mode "a" — Προσθήκη σε Αρχείο
Θυμάσαι από το προηγούμενο μάθημα: αν ανοίξουμε ένα αρχείο με mode "w", διαγράφεται ό,τι είχε. Αυτό δεν είναι πάντα αυτό που θέλουμε.
⚠️ Πρόβλημα με mode "w"
Κάθε φορά που τρέχεις το πρόγραμμα, τα παλιά δεδομένα χάνονται. Φαντάσου να γράφεις στο τετράδιό σου και κάθε φορά να σβήνεις όλες τις σημειώσεις για να γράψεις καινούργιες!
✅ Λύση: Mode "a" (append)
Το mode "a" (από το append = προσθέτω) κρατάει τα παλιά δεδομένα και προσθέτει τα νέα στο τέλος του αρχείου.
📘 Παράδειγμα — Ημερολόγιο με append
Κάθε φορά που τρέχουμε το πρόγραμμα, προσθέτουμε μια νέα εγγραφή στο diary.txt χωρίς να χάσουμε τις παλιές.
Αν τρέξουμε το πρόγραμμα 3 φορές:
Το αρχείο diary.txt θα περιέχει όλες τις σημειώσεις:
Today I learned about files Tomorrow I have an exam I need to study more
📊 Σύγκριση των 3 modes
| Mode | Τι κάνει | Πότε το χρησιμοποιούμε |
|---|---|---|
| "r" | Μόνο ανάγνωση | Όταν θέλουμε να διαβάσουμε ένα αρχείο |
| "w" | Γραφή — διαγράφει ό,τι υπήρχε | Όταν θέλουμε νέο αρχείο ή να σβήσουμε το παλιό περιεχόμενο |
| "a" | Προσθήκη στο τέλος | Όταν θέλουμε να προσθέσουμε χωρίς να χάσουμε τα παλιά |
9.8 Πρακτικό Παράδειγμα — Απλή Λίστα Αγορών
Ας φτιάξουμε ένα απλό πρόγραμμα που:
- Ζητάει από τον χρήστη να εισάγει προϊόντα
- Τα αποθηκεύει σε αρχείο
- Μετά τα διαβάζει και τα εμφανίζει
📋 Μέρος 1 — Γραφή λίστας αγορών
📋 Μέρος 2 — Ανάγνωση λίστας αγορών
✅ Τι μάθαμε από αυτό το παράδειγμα
- Συνδυάσαμε ανάγνωση από χρήστη (scanf) και γραφή σε αρχείο (fprintf)
- Χρησιμοποιήσαμε fgets για ανάγνωση γραμμής-γραμμής
- Ο βρόχος while τρέχει μέχρι να επιστρέψει NULL η fgets (τέλος αρχείου)
9.9 Συχνά Λάθη
❌ Λάθος 1: Ξέχασες να ελέγξεις αν το αρχείο άνοιξε
Σωστό: Πάντα έλεγχε αν ο pointer είναι NULL.
❌ Λάθος 2: Ξέχασες να κλείσεις το αρχείο
Σωστό: Κάθε fopen θέλει το δικό του fclose.
❌ Λάθος 3: Χρήση "w" ενώ ήθελες "a"
Σωστό: Αν θέλεις να προσθέσεις σε υπάρχον αρχείο, χρησιμοποίησε "a".
❌ Λάθος 4: Βάζεις & σε string με fscanf
Θυμήσου: Το όνομα ενός πίνακα χαρακτήρων είναι ήδη διεύθυνση!
❌ Λάθος 5: Ελέγχεις fgetc με χαρακτήρα αντί για EOF
💡 Γιατί int και όχι char;
Το EOF έχει τιμή -1 και ένας char δεν χωράει όλες τις δυνατές τιμές που μπορεί να επιστρέψει η fgetc. Γι' αυτό, στην ακαδημαϊκή πρακτική, χρησιμοποιούμε int.
9.10 Πίνακας Όλων των Συναρτήσεων Αρχείων
| Συνάρτηση | Τι κάνει | Παράδειγμα |
|---|---|---|
| fopen() | Ανοίγει αρχείο | fp = fopen("a.txt","r"); |
| fclose() | Κλείνει αρχείο | fclose(fp); |
| fprintf() | Γράφει μορφοποιημένα | fprintf(fp,"%d",x); |
| fscanf() | Διαβάζει μορφοποιημένα | fscanf(fp,"%d",&x); |
| fputc() | Γράφει έναν χαρακτήρα | fputc('A', fp); |
| fgetc() | Διαβάζει έναν χαρακτήρα | c = fgetc(fp); |
| fputs() | Γράφει string | fputs("Hello\n", fp); |
| fgets() | Διαβάζει γραμμή | fgets(line,100,fp); |
9.11 Ασκήσεις
✏️ Ασκήσεις για εξάσκηση
- Γράψε ένα πρόγραμμα που δημιουργεί ένα αρχείο numbers.txt και γράφει μέσα τους αριθμούς από το 1 έως το 10, έναν σε κάθε γραμμή.
- Γράψε ένα πρόγραμμα που διαβάζει το αρχείο numbers.txt και υπολογίζει το άθροισμα όλων των αριθμών.
- Γράψε ένα πρόγραμμα που διαβάζει ένα αρχείο κειμένου και μετράει πόσα φωνήεντα (a, e, i, o, u) υπάρχουν μέσα.
- Φτιάξε ένα πρόγραμμα που ζητάει από τον χρήστη 5 ονόματα φοιτητών και τα αποθηκεύει στο αρχείο students.txt.
- Γράψε ένα πρόγραμμα που αντιγράφει ένα αρχείο σε ένα άλλο χρησιμοποιώντας fgetc και fputc.
- (Δύσκολο) Φτιάξε ένα μενού με επιλογές: (1) Προσθήκη σημείωσης, (2) Προβολή όλων των σημειώσεων, (3) Έξοδος. Χρησιμοποίησε mode "a" για την προσθήκη.
🎯 Ανακεφαλαίωση
Σε αυτό το μάθημα μάθαμε:
- ✓ Η fscanf() δουλεύει όπως η scanf(), αλλά διαβάζει από αρχείο
- ✓ Οι fputc() και fgetc() δουλεύουν με έναν χαρακτήρα τη φορά
- ✓ Η fputs() είναι ο απλός τρόπος να γράψουμε ένα string
- ✓ Το EOF μας λέει ότι φτάσαμε στο τέλος του αρχείου
- ✓ Το mode "a" προσθέτει δεδομένα χωρίς να σβήνει τα παλιά
- ✓ Πάντα ελέγχουμε αν το αρχείο άνοιξε και πάντα κάνουμε fclose