Μάθημα 9: Αρχεία στη C — Μέρος 2

Modes "+" , fscanf, fputc, fgetc, fputs, EOF και Mode "a"

9.1 Σύνοψη Μαθήματος 8

Στο προηγούμενο μάθημα μάθαμε ότι τα αρχεία μας επιτρέπουν να αποθηκεύουμε δεδομένα μόνιμα στον σκληρό δίσκο. Ας θυμηθούμε τα βασικά:

1. fopen()
άνοιγμα
2. εγγραφή /
ανάγνωση
3. fclose()
κλείσιμο

📋 Τι ξέρουμε μέχρι τώρα

fopen() → ανοίγεις ένα αρχείο 👉 Σαν να ανοίγεις ένα τετράδιο

  • "r" = μόνο διάβασμα (δεν γράφεις)
  • "w" = γράφεις από την αρχή (σβήνει ό,τι είχε)
  • "a" = προσθέτεις στο τέλος

fprintf() → γράφεις μέσα στο αρχείο 👉 Σαν να γράφεις προτάσεις στο τετράδιο (όπως printf, αλλά αντί για οθόνη → πάει στο αρχείο)

fgets() → διαβάζεις μια γραμμή από το αρχείο 👉 Σαν να διαβάζεις μία σειρά από το τετράδιο κάθε φορά

fclose() → κλείνεις το αρχείο 👉 Σαν να κλείνεις το τετράδιο (σημαντικό για να σωθούν σωστά τα δεδομένα)

📖 "r" → ΔΙΑΒΑΣΜΑ μόνο

👉 Δεν γράφεις τίποτα, απλά διαβάζεις

Παράδειγμα:

FILE *f = fopen("data.txt", "r");

📌 Σημαίνει:
Άνοιξε το αρχείο για να το διαβάσω

✍️ "w" → ΓΡΑΨΙΜΟ από την αρχή

👉 Σβήνει ό,τι υπήρχε και γράφει από το μηδέν

Παράδειγμα:

FILE *f = fopen("data.txt", "w"); fprintf(f, "Hello");

📌 Σημαίνει:
Το αρχείο γίνεται ΚΕΝΟ και μετά γράφω "Hello"

"a" → ΠΡΟΣΘΗΚΗ στο τέλος

👉 Δεν σβήνει τίποτα, απλά προσθέτει

Παράδειγμα:

FILE *f = fopen("data.txt", "a"); fprintf(f, "Hello");

📌 Σημαίνει:
Ό,τι υπάρχει μένει όπως είναι και προσθέτω "Hello" στο τέλος

Σε αυτό το μάθημα θα γνωρίσουμε νέες συναρτήσεις που μας δίνουν περισσότερες δυνατότητες:

9.2 Modes "r+", "w+", "a+"

Εκτός από τα βασικά modes "r", "w", "a", υπάρχουν και οι εκδοχές με + που επιτρέπουν διάβασμα ΚΑΙ γράψιμο στο ίδιο αρχείο.

"r+" → Διάβασμα ΚΑΙ γράψιμο

👉 Δεν σβήνει το αρχείο

FILE *f = fopen("data.txt", "r+");

📌 Σημαίνει:
Μπορώ να διαβάζω ΚΑΙ να γράφω μέσα στο ίδιο αρχείο (αλλά το αρχείο πρέπει να υπάρχει ήδη)

✍️ "w+" → Διάβασμα ΚΑΙ γράψιμο (από την αρχή)

👉 Σβήνει τα πάντα

FILE *f = fopen("data.txt", "w+");

📌 Σημαίνει:
Καθαρίζει το αρχείο και μετά μπορώ να γράψω και να διαβάσω

"a+" → Διάβασμα ΚΑΙ προσθήκη στο τέλος

👉 Δεν σβήνει τίποτα

FILE *f = fopen("data.txt", "a+");

📌 Σημαίνει:
Διαβάζω ό,τι υπάρχει και ό,τι γράφω πάει στο τέλος

9.2.1 📘 Πρακτικό Παράδειγμα — Χρήση "r+"

#include <stdio.h> int main() { // 📂 Ανοίγω το αρχείο για διάβασμα + γράψιμο (r+) FILE *f = fopen("data.txt", "r+"); // ❗ Έλεγχος αν άνοιξε σωστά το αρχείο if (f == NULL) { printf("Δεν άνοιξε το αρχείο\n"); return 1; // σταματάει το πρόγραμμα αν υπάρχει πρόβλημα } // 📦 Πίνακας χαρακτήρων (string) // εδώ θα αποθηκεύσουμε μια γραμμή από το αρχείο char line[100]; // 📖 fgets = διαβάζει μια γραμμή από αρχείο // fgets(line, 100, f); // | | | // | | └── f = το αρχείο από το οποίο διαβάζουμε (FILE pointer) // | | // | └── 100 = μέγιστοι χαρακτήρες που θα διαβαστούν // | 👉 στην πράξη διαβάζει μέχρι 99 χαρακτήρες // | (γιατί 1 θέση κρατιέται για το '\0') // | // └── line = ο πίνακας όπου αποθηκεύεται η γραμμή (string) // 📖 Διαβάζω την ΠΡΩΤΗ γραμμή από το αρχείο fgets(line, 100, f); // 🖨️ Τυπώνω τι διάβασα printf("Διάβασα: %s\n", line); // ✍️ Γράφω νέο κείμενο στο αρχείο // ⚠️ Προσοχή: γράφει από τη θέση που βρίσκεται ο "δείκτης" του αρχείου fprintf(f, "\nNEO KEIMENO"); // 🚪 Κλείνω το αρχείο (πολύ σημαντικό για αποθήκευση αλλαγών) fclose(f); return 0; }

Πάμε να το δούμε σαν "ζωντανή εκτέλεση" βήμα–βήμα 👍

📁 Δείγμα αρχείου data.txt πριν τρέξει το πρόγραμμα

HELLO WORLD
C PROGRAMMING
STUDY FILES

▶️ Τι κάνει το πρόγραμμα

1) Άνοιγμα αρχείου (r+)

FILE *f = fopen("data.txt", "r+");

👉 Το αρχείο ανοίγει ΧΩΡΙΣ να σβηστεί τίποτα
👉 Ο "δείκτης" είναι στην αρχή του αρχείου

2) fgets

fgets(line, 100, f);

👉 Διαβάζει την 1η γραμμή

Άρα:

HELLO WORLD

μπαίνει μέσα στο line

Μετά το fgets(line, 100, f); γίνεται έτσι:

line = [ 'H' ][ 'E' ][ 'L' ][ 'L' ][ 'O' ][ ' ' ][ 'W' ][ 'O' ][ 'R' ][ 'L' ][ 'D' ][ '\n' ][ '\0' ][ ...κενά... ]

3) printf

printf("Διάβασα: %s\n", line);

🖨️ Έξοδος στην οθόνη:

Διάβασα: HELLO WORLD

Πώς το κάνει το printf("%s", line);

Το %s λέει στη C:

"Ξεκίνα από τον πρώτο χαρακτήρα και συνέχισε μέχρι να βρεις '\0'"

👉 Άρα η ίδια η printf έχει μέσα της έναν μηχανισμό που κάνει κάτι σαν loop.

🧠 Δηλαδή είναι ισοδύναμο με:

for (int i = 0; line[i] != '\0'; i++) { printf("%c", line[i]); }

4) fprintf

fprintf(f, "\nNEO KEIMENO");

⚠️ ΣΗΜΑΝΤΙΚΟ (το κλειδί της άσκησης)

Μετά το 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

📘 Ανάγνωση και Δεύτερης Γραμμής

#include <stdio.h> int main() { FILE *f = fopen("data.txt", "r"); if (f == NULL) { printf("Error\n"); return 1; } char line[100]; // 📖 1η γραμμή fgets(line, 100, f); printf("1η γραμμή: %s", line); // 📖 2η γραμμή fgets(line, 100, f); printf("2η γραμμή: %s", line); fclose(f); return 0; }

9.2.2 📘 Πρακτικό Παράδειγμα — Χρήση "w+"

Παράδειγμα "w+" με σχόλια

#include <stdio.h> int main() { // 📂 Ανοίγω αρχείο με "w+" // 👉 σβήνει ΟΛΑ τα παλιά δεδομένα // 👉 μπορώ να γράψω ΚΑΙ να διαβάσω FILE *f = fopen("data.txt", "w+"); // ❗ Έλεγχος αν άνοιξε σωστά if (f == NULL) { printf("Δεν άνοιξε το αρχείο\n"); return 1; } // ✍️ Γράφω στο αρχείο από την αρχή fprintf(f, "HELLO WORLD\n"); fprintf(f, "C PROGRAMMING\n"); // 📌 Πολύ σημαντικό: // Ο δείκτης τώρα είναι ΣΤΟ ΤΕΛΟΣ του αρχείου // άρα για να διαβάσω πρέπει να τον πάω στην αρχή rewind(f); // 🔁 γυρνάει τον δείκτη στην αρχή του αρχείου // 📦 πίνακας για ανάγνωση char line[100]; // 📖 διαβάζω 1η γραμμή fgets(line, 100, f); printf("1η: %s", line); // 📖 διαβάζω 2η γραμμή fgets(line, 100, f); printf("2η: %s", line); fclose(f); return 0; }

📁 ΤΙ ΥΠΑΡΧΕΙ ΣΤΟ ΑΡΧΕΙΟ (μετά το w+)

HELLO WORLD
C PROGRAMMING

🧠 ΤΙ ΣΥΜΒΑΙΝΕΙ ΒΗΜΑ-ΒΗΜΑ

1️⃣ w+

👉 σβήνει ΟΛΟ το αρχείο
(ό,τι υπήρχε πριν → εξαφανίζεται 💥)

2️⃣ fprintf

👉 γράφει καινούριο περιεχόμενο:

HELLO WORLD C PROGRAMMING

3️⃣ rewind(f)

👉 γυρνάει τον δείκτη στην αρχή

4️⃣ fgets

👉 διαβάζει γραμμή-γραμμή όπως πριν

9.2.3 📘 Πρακτικό Παράδειγμα — Χρήση "a+"

Παράδειγμα με "a+"

#include <stdio.h> int main() { // 📂 Ανοίγω αρχείο με "a+" // 👉 αν δεν υπάρχει, το δημιουργεί // 👉 ΔΕΝ σβήνει τίποτα // 👉 γράφει ΠΑΝΤΑ στο τέλος FILE *f = fopen("data.txt", "a+"); if (f == NULL) { printf("Δεν άνοιξε το αρχείο\n"); return 1; } // ✍️ Γράφω στο τέλος του αρχείου fprintf(f, "HELLO WORLD\n"); fprintf(f, "C PROGRAMMING\n"); // ⚠️ ΣΗΜΑΝΤΙΚΟ: // Ο δείκτης είναι τώρα στο ΤΕΛΟΣ του αρχείου // άρα για να διαβάσω πρέπει να γυρίσω πίσω rewind(f); // 🔁 πάει στην αρχή // 📦 buffer για ανάγνωση char line[100]; // 📖 διαβάζω γραμμή-γραμμή while (fgets(line, 100, f) != NULL) { printf("%s", line); } fclose(f); return 0; }

📁 ΤΙ ΥΠΑΡΧΕΙ ΣΤΟ ΑΡΧΕΙΟ

👉 Αν το αρχείο ΞΕΚΙΝΑ άδειο:

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 → μόνο διάβασμα

fopen("data.txt", "r");

📌 r+ → διάβασμα + γράψιμο

fopen("data.txt", "r+");

⚡ Σύγκριση r / r+

mode read write delete file file must exist
r
r+

🟡 2. w vs w+

📌 w → μόνο γράψιμο

fopen("data.txt", "w");

📌 w+ → γράψιμο + διάβασμα

fopen("data.txt", "w+");

⚡ Σύγκριση w / w+

mode read write delete file create file
w
w+

🟢 3. a vs a+

📌 a → μόνο προσθήκη

fopen("data.txt", "a");

📌 a+ → προσθήκη + διάβασμα

fopen("data.txt", "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() που ήδη ξέρεις — η μόνη διαφορά είναι ότι διαβάζει από αρχείο αντί για το πληκτρολόγιο.

📝 Σύνταξη

fscanf(fp, "format string", &variable);

💡 Σύγκριση με scanf

scanf (πληκτρολόγιο) fscanf (αρχείο)
scanf("%d", &age); fscanf(fp, "%d", &age);
scanf("%s", name); fscanf(fp, "%s", name);

Ο κανόνας είναι απλός: αν ξέρεις scanf, ξέρεις και fscanf — απλά βάζεις τον fp ως πρώτη παράμετρο.

📘 Παράδειγμα — Ανάγνωση αριθμού από αρχείο

Ας υποθέσουμε ότι έχουμε ένα αρχείο age.txt που περιέχει:

25

Ο κώδικας για να διαβάσουμε αυτόν τον αριθμό:

#include <stdio.h> int main() { int age; /* Άνοιγμα αρχείου για ανάγνωση */ FILE *fp = fopen("age.txt", "r"); /* Έλεγχος αν άνοιξε σωστά */ if (fp == NULL) { printf("Error: Cannot open file!\n"); return 1; } /* Διάβασμα ενός ακεραίου από το αρχείο */ fscanf(fp, "%d", &age); /* Εκτύπωση στην οθόνη */ printf("Age from file: %d\n", age); fclose(fp); return 0; }
Age from file: 25

📘 Παράδειγμα — Ανάγνωση ονόματος και βαθμού

Αρχείο student.txt:

Giorgos 8.5
#include <stdio.h> int main() { char name[50]; float grade; FILE *fp = fopen("student.txt", "r"); if (fp == NULL) { printf("Error opening file!\n"); return 1; } /* Διαβάζουμε ΔΥΟ τιμές: ένα string και ένα float */ fscanf(fp, "%s %f", name, &grade); printf("Student: %s\n", name); printf("Grade: %.2f\n", grade); fclose(fp); return 0; }
Student: Giorgos Grade: 8.50

⚠️ Προσοχή

Θυμήσου: για int και float βάζουμε & (διεύθυνση), αλλά για string (πίνακα χαρακτήρων) ΟΧΙ. Το όνομα του πίνακα είναι ήδη διεύθυνση!

9.4 fputc() και fgetc() — Χαρακτήρας-Χαρακτήρας

Μερικές φορές θέλουμε να δουλέψουμε με αρχεία έναν χαρακτήρα τη φορά. Γι' αυτό έχουμε δύο απλές συναρτήσεις:

Συνάρτηση Τι κάνει
fputc(c, fp) Γράφει έναν χαρακτήρα c στο αρχείο
fgetc(fp) Διαβάζει έναν χαρακτήρα από το αρχείο

📘 Παράδειγμα — Γραφή χαρακτήρων με fputc()

#include <stdio.h> int main() { FILE *fp = fopen("hello.txt", "w"); if (fp == NULL) { printf("Error!\n"); return 1; } /* Γράφουμε έναν-έναν τους χαρακτήρες */ fputc('H', fp); fputc('i', fp); fputc('!', fp); fclose(fp); return 0; }

Μετά την εκτέλεση, το αρχείο hello.txt περιέχει:

Hi!

📘 Παράδειγμα — Ανάγνωση ολόκληρου αρχείου με fgetc()

Το πιο κλασικό μοτίβο: διαβάζουμε όλο το αρχείο χαρακτήρα-χαρακτήρα και το εμφανίζουμε στην οθόνη.

#include <stdio.h> int main() { char c; FILE *fp = fopen("hello.txt", "r"); if (fp == NULL) { printf("Error!\n"); return 1; } /* Διαβάζουμε έναν χαρακτήρα κάθε φορά, */ /* μέχρι να φτάσουμε στο τέλος του αρχείου (EOF) */ while ((c = fgetc(fp)) != EOF) { printf("%c", c); } fclose(fp); return 0; }
Hi!

💡 Πώς λειτουργεί το while;

Σε κάθε επανάληψη:

  1. Η fgetc(fp) διαβάζει έναν χαρακτήρα
  2. Τον αποθηκεύει στη μεταβλητή c
  3. Αν ο χαρακτήρας δεν είναι EOF, εκτελείται το σώμα του βρόχου
  4. Όταν φτάσει στο τέλος, η fgetc επιστρέφει EOF και ο βρόχος σταματάει

9.5 fputs() — Γραφή Ολόκληρης Γραμμής

Η fputs() είναι η απλούστερη συνάρτηση για να γράψουμε ένα string σε αρχείο. Είναι πιο απλή από την fprintf() γιατί δεν έχει format specifiers — απλά γράφει το string όπως είναι.

📝 Σύνταξη

fputs("text", fp);

💡 Διαφορά από fprintf()

  • fprintf(fp, "Hello\n"); — ίδιο αποτέλεσμα, αλλά πιο "βαριά" συνάρτηση
  • fputs("Hello\n", fp); — απλή, γρήγορη, για απλά strings

Προσοχή: Καμία από τις δύο συναρτήσεις δεν προσθέτει αυτόματα \n. Αν θες νέα γραμμή, πρέπει να τη γράψεις εσύ μέσα στο string (όπως στα παραδείγματα παραπάνω).

📘 Παράδειγμα — Γραφή λίστας φρούτων

#include <stdio.h> int main() { FILE *fp = fopen("fruits.txt", "w"); if (fp == NULL) { printf("Error!\n"); return 1; } /* Γράφουμε 3 γραμμές — μια για κάθε φρούτο */ fputs("Apple\n", fp); fputs("Banana\n", fp); fputs("Orange\n", fp); fclose(fp); printf("File saved!\n"); return 0; }

Το αρχείο 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.

#include <stdio.h> int main() { char c; int count = 0; /* μετρητής χαρακτήρων */ FILE *fp = fopen("fruits.txt", "r"); if (fp == NULL) { printf("Error!\n"); return 1; } /* Διαβάζουμε μέχρι το τέλος του αρχείου */ while ((c = fgetc(fp)) != EOF) { count++; /* αύξηση μετρητή */ } printf("Total characters: %d\n", count); fclose(fp); return 0; }
Total characters: 20

Μετράει και τους χαρακτήρες \n (νέα γραμμή) που είναι κι αυτοί κανονικοί χαρακτήρες μέσα στο αρχείο.

📘 Παράδειγμα — Μέτρηση γραμμών

Μια μικρή παραλλαγή: αντί για χαρακτήρες, μετράμε γραμμές. Μια γραμμή τελειώνει όταν συναντήσουμε \n.

#include <stdio.h> int main() { char c; int lines = 0; FILE *fp = fopen("fruits.txt", "r"); if (fp == NULL) { printf("Error!\n"); return 1; } /* Κάθε φορά που βρίσκουμε \n, μετράμε μια γραμμή */ while ((c = fgetc(fp)) != EOF) { if (c == '\n') { lines++; } } printf("Total lines: %d\n", lines); fclose(fp); return 0; }
Total lines: 3

9.7 Mode "a" — Προσθήκη σε Αρχείο

Θυμάσαι από το προηγούμενο μάθημα: αν ανοίξουμε ένα αρχείο με mode "w", διαγράφεται ό,τι είχε. Αυτό δεν είναι πάντα αυτό που θέλουμε.

⚠️ Πρόβλημα με mode "w"

Κάθε φορά που τρέχεις το πρόγραμμα, τα παλιά δεδομένα χάνονται. Φαντάσου να γράφεις στο τετράδιό σου και κάθε φορά να σβήνεις όλες τις σημειώσεις για να γράψεις καινούργιες!

✅ Λύση: Mode "a" (append)

Το mode "a" (από το append = προσθέτω) κρατάει τα παλιά δεδομένα και προσθέτει τα νέα στο τέλος του αρχείου.

📘 Παράδειγμα — Ημερολόγιο με append

Κάθε φορά που τρέχουμε το πρόγραμμα, προσθέτουμε μια νέα εγγραφή στο diary.txt χωρίς να χάσουμε τις παλιές.

#include <stdio.h> int main() { char note[200]; /* Άνοιγμα με mode "a" — προσθήκη στο τέλος */ FILE *fp = fopen("diary.txt", "a"); if (fp == NULL) { printf("Error!\n"); return 1; } printf("Write a note: "); fgets(note, 200, stdin); /* Προσθήκη της νέας σημείωσης στο τέλος */ fputs(note, fp); fclose(fp); printf("Note saved!\n"); return 0; }

Αν τρέξουμε το πρόγραμμα 3 φορές:

Write a note: Today I learned about files Note saved! Write a note: Tomorrow I have an exam Note saved! Write a note: I need to study more Note saved!

Το αρχείο 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. Τα αποθηκεύει σε αρχείο
  3. Μετά τα διαβάζει και τα εμφανίζει

📋 Μέρος 1 — Γραφή λίστας αγορών

#include <stdio.h> int main() { char item[50]; int i; /* Άνοιγμα αρχείου για γραφή */ FILE *fp = fopen("shopping.txt", "w"); if (fp == NULL) { printf("Error!\n"); return 1; } printf("Enter 3 items:\n"); /* Ζητάμε 3 προϊόντα και τα γράφουμε στο αρχείο */ for (i = 1; i <= 3; i++) { printf("Item %d: ", i); scanf("%s", item); /* Γράφουμε το προϊόν στο αρχείο + νέα γραμμή */ fprintf(fp, "%s\n", item); } fclose(fp); printf("\nShopping list saved!\n"); return 0; }
Enter 3 items: Item 1: Bread Item 2: Milk Item 3: Coffee Shopping list saved!

📋 Μέρος 2 — Ανάγνωση λίστας αγορών

#include <stdio.h> int main() { char line[50]; int num = 1; /* Άνοιγμα αρχείου για ανάγνωση */ FILE *fp = fopen("shopping.txt", "r"); if (fp == NULL) { printf("Error: file not found!\n"); return 1; } printf("===== SHOPPING LIST =====\n"); /* Διαβάζουμε γραμμή-γραμμή μέχρι το τέλος */ while (fgets(line, 50, fp) != NULL) { printf("%d. %s", num, line); num++; } printf("=========================\n"); fclose(fp); return 0; }
===== SHOPPING LIST ===== 1. Bread 2. Milk 3. Coffee =========================

✅ Τι μάθαμε από αυτό το παράδειγμα

  • Συνδυάσαμε ανάγνωση από χρήστη (scanf) και γραφή σε αρχείο (fprintf)
  • Χρησιμοποιήσαμε fgets για ανάγνωση γραμμής-γραμμής
  • Ο βρόχος while τρέχει μέχρι να επιστρέψει NULL η fgets (τέλος αρχείου)

9.9 Συχνά Λάθη

❌ Λάθος 1: Ξέχασες να ελέγξεις αν το αρχείο άνοιξε

/* Λάθος — χωρίς έλεγχο */ FILE *fp = fopen("data.txt", "r"); fgetc(fp); /* αν το αρχείο δεν υπάρχει → crash! */

Σωστό: Πάντα έλεγχε αν ο pointer είναι NULL.

❌ Λάθος 2: Ξέχασες να κλείσεις το αρχείο

FILE *fp = fopen("data.txt", "w"); fprintf(fp, "Hello"); /* Ξέχασα το fclose() → τα δεδομένα μπορεί να χαθούν! */ return 0;

Σωστό: Κάθε fopen θέλει το δικό του fclose.

❌ Λάθος 3: Χρήση "w" ενώ ήθελες "a"

/* Λάθος — σβήνει το παλιό περιεχόμενο */ FILE *fp = fopen("log.txt", "w"); fprintf(fp, "New entry\n");

Σωστό: Αν θέλεις να προσθέσεις σε υπάρχον αρχείο, χρησιμοποίησε "a".

❌ Λάθος 4: Βάζεις & σε string με fscanf

/* Λάθος */ fscanf(fp, "%s", &name); /* Σωστό */ fscanf(fp, "%s", name);

Θυμήσου: Το όνομα ενός πίνακα χαρακτήρων είναι ήδη διεύθυνση!

❌ Λάθος 5: Ελέγχεις fgetc με χαρακτήρα αντί για EOF

/* Λάθος — το EOF είναι τιμή int, όχι char */ char c; while (c = fgetc(fp), c != EOF) /* προβληματικό */ /* Σωστό — χρησιμοποιούμε int */ int c; while ((c = fgetc(fp)) != 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 Ασκήσεις

✏️ Ασκήσεις για εξάσκηση

  1. Γράψε ένα πρόγραμμα που δημιουργεί ένα αρχείο numbers.txt και γράφει μέσα τους αριθμούς από το 1 έως το 10, έναν σε κάθε γραμμή.
  2. Γράψε ένα πρόγραμμα που διαβάζει το αρχείο numbers.txt και υπολογίζει το άθροισμα όλων των αριθμών.
  3. Γράψε ένα πρόγραμμα που διαβάζει ένα αρχείο κειμένου και μετράει πόσα φωνήεντα (a, e, i, o, u) υπάρχουν μέσα.
  4. Φτιάξε ένα πρόγραμμα που ζητάει από τον χρήστη 5 ονόματα φοιτητών και τα αποθηκεύει στο αρχείο students.txt.
  5. Γράψε ένα πρόγραμμα που αντιγράφει ένα αρχείο σε ένα άλλο χρησιμοποιώντας fgetc και fputc.
  6. (Δύσκολο) Φτιάξε ένα μενού με επιλογές: (1) Προσθήκη σημείωσης, (2) Προβολή όλων των σημειώσεων, (3) Έξοδος. Χρησιμοποίησε mode "a" για την προσθήκη.

🎯 Ανακεφαλαίωση

Σε αυτό το μάθημα μάθαμε:

  • Η fscanf() δουλεύει όπως η scanf(), αλλά διαβάζει από αρχείο
  • Οι fputc() και fgetc() δουλεύουν με έναν χαρακτήρα τη φορά
  • Η fputs() είναι ο απλός τρόπος να γράψουμε ένα string
  • Το EOF μας λέει ότι φτάσαμε στο τέλος του αρχείου
  • Το mode "a" προσθέτει δεδομένα χωρίς να σβήνει τα παλιά
  • Πάντα ελέγχουμε αν το αρχείο άνοιξε και πάντα κάνουμε fclose