Transcript FILE * f
הרצאה 09
עבודה עם קבצים
קרן כליף
ביחידה זו נלמד:
מוטיבציה לעבודה עם קבצים
סוגי קבצים:
בינאריים
טקסט
פעולות על קבצים (עבור שני סוגי הקבצים):
פתיחת קובץ
קריאה מקובץ
כתיבה לקובץ
סגירת קובץ
פעולות נוספותfseek, ftell, rewind, ferror, fflush, feof :
קובץ אינדקסים
2
© Keren Kalif
קבצים -מוטיבציה
כאשר כותבים תוכנה ,המידע המחושב בכל הרצה הולך
לאיבוד עם סיומה ,מאחר והתוכנה רצה בזיכרון ה RAM -של
המחשב
נרצה לשמור את המידע בין ההרצות בזיכרון הקבוע ( Hard
)Diskכדי:
ליצור תוכנה בעלת משמעות ורצף
להקל עלינו בעת בדיקות התוכנה
קריאת נתונים מקובץ מוכן מראש ולא מהמשתמש
שמירת נתונים לשימוש ע"י תוכניות אחרות
עיבוד מידע גדול בחלקים
ניתן לשמור את המידע בכמה אופנים שונים:
( DB לא יילמד בקורס זה)
3קבצים
© Keren Kalif
עבודה כללית עם קבצים -מוטיבציה
יתכן ותהייה לנו תוכנית שנרצה לשמור את הפלט שלה לקובץ
יתכן ותהייה לנו תוכנית שנרצה שהקלט שלה יהיה מקובץ,
ולא מהמקלדת
דוגמא:
קריאת אוסף מספרים מקובץ בפורמט ידוע מראש והצגת
סכום המספרים
כתיבת תוכנית המכינה דו"ח כלשהו ושומרת את הדוח
בקובץ ,בנוסף להצגתו על המסך
4
© Keren Kalif
סוגי קבצים
קובץ טקסט:
כתוב בשפה אותה אנו יכולים לקרוא ולהבין
קובץ בינארי:
לא ניתן להבין את התוכן ,מהווה העתק תמונת הזכרון של
המחשב
5
© Keren Kalif
המבנה FILE
קובץ הוא משתנה מטיפוס FILEהמכיל שדות רבים עם מידע
על הקובץ
מוגדר בstdio.h -
הפונקציות לעבודה עם קבצים תמיד מקבלות מצביע למבנה
זה כדי לא לשכפל את כל המבנה במעבר לפונקציות משום
וזהו מבנה עם הרבה נתונים
6
© Keren Kalif
מבנה עבודה כללי עם קבצים
לכתיבה תוך ציון/ בתחילת העבודה יש לפתוח קובץ לקריאה
האם זהו קובץ טקסט או בינארי
יש לבדוק האם פתיחה הצליחה
לבסוף יש לסגור את הקובץ
1. void main()
2. {
3.
FILE* f = fopen(<file name>, <open parameters>);
4.
if (f == NULL)
5.
{
6.
printf("Failed opening the file. Exiting!\n");
7.
return;
8.
}
9.
// here some operation with the file..
10.
fclose(f);
11. }
© Keren Kalif
7
© Keren Kalif
פתיחת קובץ – פרמטרים לסוג הפתיחה
8
;)FILE* fopen(char* fileName, char* mode
פתיחת קובץ לקריאה“r” :
פתיחת קובץ לכתיבה:
- “w” במידה ויש נתונים בקובץ הם ידרסו
– “a” כותב לסוף קובץ (כלומר לא דורס את המידע ,אם קיים) .לא
מאפשר כתיבה לתחילת הקובץ!
פתיחת קובץ לקריאה ולכתיבה:
– “r+” הקובץ חייב להיות קיים ,יתקבל NULLאם לא
– “w+” אם הקובץ קיים ,דורס אותו
– “a+” אם הקובץ קיים כותב לסופו ,אחרת יוצר קובץ חדש .לא
מאפשר כתיבה לתחילת הקובץ!
כדי לפתוח את הקובץ כבינארי נוסיף bבסוף הפרמטר לפתיחה .למשל:
” “rb”, “wbוכו' .ברירת המחדל היא קובץ טקסט.
ניתן ב mode -הפתיחה לציין ,tעבור קובץ טקסט .למשל“wt” :
פתיחת קובץ – סיבות לכשלון
קובץ המוגדר לקריאה בלבד שמנסים לפתוח אותו לכתיבה
פתיחה ע"י " "rקובץ שאינו קיים
9
© Keren Kalif
פתיחת קובץ – מאחורי הקלעים
בעת פתיחת קובץ הוא לא נפתח ב NOTEPAD -או במשהו
דומה ,אלא חלק מהקובץ נטען מה HD -לזיכרון ה RAM -של
המחשב ,וכאשר יש צורך בהמשך הקובץ ,החלק הראשון נמחק
מה RAM -ונטען ההמשך ,וכן הלאה..
10
© Keren Kalif
סגירת קובץ
;) int fclose(FILE* file
מקבלת מצביע לקובץ ומחזירה 0אם הצליחה לסגור אותו ,אחרת
תחזיר ( -1הקבוע )EOF
תכשל למשל כאשר מנסים לסגור קובץ שאינו פתוח
;)( int fcloseall
סוגרת את כל הקבצים שפתחנו ומחזירה את מספר הקבצים
שסגרה
רק כאשר סוגרים את הקובץ כל הנתונים שכתבנו נשמרים .אם
הייתה הפסקת חשמל באמצע נאבד את כל השינויים..
11
© Keren Kalif
כתיבה לקובץ טקסט
פקודות הכתיבה לקובץ טקסט הן כמו הפקודות
לכתיבה למסך ,פרט לכך ש:
שמן מתחיל עם f
הן מקבלות פרמטר נוסף שהוא מצביע לקובץ אליו רוצים
לכתוב
הן תמיד יכתבו למקום בו הסמן נמצא
הסמן מתקדם עם הכתיבה
;) int fprintf(FILE* , char*, ...
;)* int fputs(char*, FILE
;)* int fputc(char, FILE
12
© Keren Kalif
)1( כתיבה לקובץ טקסט – דוגמא
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
#include <stdio.h>
void main()
{
FILE* f = fopen("myFile.txt", "w");
int res;
דריסת הקובץ אם קיים
if (f == NULL)
{
printf("Failed opening the file. Exiting!\n");
return;
}
fprintf(f, "%s %d %lf\n", "KerenK", 28, 99.8);
fputs("Hello World!", f);
fputc('A', f);
fclose(f);
}
© Keren Kalif
13
)2( כתיבה לקובץ טקסט – דוגמא
1. #include <stdio.h>
2.
3. void main()
4. {
5.
6.
7.
8.
9.
10.
11.
12.
13.
FILE* f = fopen("myFile.txt", "w");
int res;
if (f == NULL)
{
printf("Failed opening the file. Exiting!\n");
return;
}
fputs("Hello World!\n", f);
fclose(f);
14.
15.
16.
17.
f = fopen("myFile.txt", "a");
fputs("And Good Morning!\n", f);
fclose(f);
פתיחת הקובץ וכתיבה לסופו
18. }
© Keren Kalif
14
)3( כתיבה לקובץ טקסט – דוגמא
1. #include <stdio.h>
2.
3. void main()
4. {
5.
6.
7.
8.
9.
10.
11.
12.
13.
FILE* f = fopen("myFile.txt", "w");
int res;
if (f == NULL)
{
printf("Failed opening the file. Exiting!\n");
return;
}
fputs("Hello World!\n", f);
fclose(f);
14.
15.
16.
17.
f = fopen)"myFile.txt", “w");
fputs("And Good Morning!\n", f);
fclose(f);
...דריסת הקובץ הקודם
18. }
© Keren Kalif
15
הפקודה fflush
הנתונים נשמרים לקובץ רק לאחר סגירתו
אם רוצים לשמור את הנתונים תוך כדי ניתן להשתמש בפקודה
)void fflush(FILE* f
המעדכנת את נתוני הקובץ ששונו ב RAM -לHD -
פתיחת הקובץ ב notepad -בין פקודת הכתיבה
תראה קובץ ריק ,ונראה אותו מעודכן רק לאחר
הפקודה .fclose
עם הפקודה fflushהקובץ יתעדכן מיידית.
16
© Keren Kalif
)(1. void main
{ 2.
3.
;)"FILE* f = fopen("test.txt", "w
4.
5.
;)fputs("Hello World!\n", f
6.
;)// fflush(f
7.
;)fputs("And Good Morning!\n", f
8.
9.
;)fclose(f
} 10.
שמירה וקריאה מקובץ -כללי
17
כאשר נשמור מידע לקובץ ,אנו בוחרים לשמור את המידע בסדר
מסוים
צריכה להיות התאמה בין סדר כתיבת הנתונים לקובץ לסדר
קריאת הנתונים מהקובץ
למשל :אם כתבתי מידע על סטודנט בסדר הבא :שם ,ת.ז .וגיל,
גם סדר קריאת הנתונים יהיה זהה
כלומר ,צריכה להיות הסכמה וידיעה בין מי שכותב לקובץ ומי
שקורא ממנו לגבי סדר הנתונים בקובץ
© Keren Kalif
קריאה מקובץ טקסט
פקודות הקריאה לקובץ טקסט הן כמו הפקודות הקריאה למסך,
פרט לכך ש:
שמן מתחיל עם f
הן מקבלות פרמטר נוסף שהוא מצביע לקובץ אליו רוצים לכתוב
מקבלות גם את כמות התווים לקריאה.
קוראת עד ’ ‘\nאו עד n-1תווים
;) int fscanf(FILE* , char*, ...
מחזירה את כמות האיברים שקראה בהצלחה
;)* char* fgets(char*, int n, FILE
מחזירה את המחרוזת שקראה או NULLאם לא הצליחה (למשל הקובץ
נגמר)
;)* int fgetc(FILE
מחזירה את ערך האסקיי של התו או את הקבוע ( EOFשערכו )-1אם
לא הצליחה (למשל הקובץ נגמר)
18
© Keren Kalif
1. #define SIZE 20
2. void main()
קריאה מקובץ טקסט – דוגמא
3. {
4.
5.
6.
7.
8.
char str[]="Hi", sentence[]="Hello World!", str2[SIZE], sentence2[SIZE];
int num1=6, num2=0;
float f1=4.5, f2=0;
FILE* f = fopen("myFile.txt", "w");
// check if open file succeeded..
9.
10.
11.
12.
fputs(sentence, f);
fprintf(f, "\n%d %f %s\n", num1, f1, str);
fclose(f);
13.
14.
15.
16.
17.
printf("Before reading from file:\nnum2=%d f2=%f str=|%s| sentence2=|%s|\n",
num2, f2, str2, sentence2);
f = fopen("myFile.txt", "r");
// check if open file succeeded..
18.
19.
20.
fgets(sentence2, SIZE, f);
fscanf(f, "%d %f %s", &num2, &f2, str2);
21.
22.
23.
24.
25. }
printf("\nAfter reading from file:\nnum2=%d f2=%f str=|%s| sentence2=|%s|\n",
num2, f2, str2, sentence2);
fclose(f);
© Keren Kalif
19
1.
void main()
2.
{
3.
FILE* f;
4.
char str1[] = "hello world", str2[20] = "", word[10];
5.
int num1 = 5, num2, rc = 0, fReadSentence=1;
בדיקת כמות הקריאות
scanf המוצלחות של
6.
7.
f = fopen("test.txt", "w"); // check open file succeed...
8.
fprintf(f, "%s %d\n", str1, num1);
9.
fclose(f);
10.
11.
f = fopen("test.txt", "r"); // check open file succeed...
12.
while (fReadSentence)
13.
{
14.
fscanf(f, "%s", word);
15.
rc = sscanf(word, "%d", &num2);
16.
if (rc == 0)
17.
{
18.
if (strcmp(str2, "") != 0)
19.
strcat(str2, word);
strcat(str2, " ");
}
20.
else
21.
22.
}
23.
fclose(f);
24.
יש לקרוא שורה מקובץ קובץ ובה משפט
.(מספר המילים אינו ידוע) ומספר
יש לקרוא את המשפט לתוך מחרוזת ואת
.int המספר לתוך
}
fReadSentence =0;
© Keren Kalif
20
feof
;) int feof (FILE * stream
פונקציה זו מקבלת קובץ פתוח ומחזירה 0אם לא הגענו לסוף
הקובץ ,ו )EOF( -1 -במידה והגענו לסוף
21
© Keren Kalif
1. void main()
דוגמא – העתקת קובץ
2. {
3.
4.
5.
6.
char ch;
FILE* fSource, *fDest;
fSource = fopen("example.txt", "r");
// check if open file succeeded..
7.
8.
9.
fDest = fopen("exampleCopy.txt", "w");
// check if open file succeeded..
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20. }
ch = fgetc(fSource);
while (!feof(fSource)) // OR: (ch != EOF)
{
fputc(ch, fDest);
ch = fgetc(fSource);
}
fclose(fSource); // returns 0 since close file succeed fcloseall();
// returns 2 since
fclose(fDest); // returns 0 since close file succeed
closed 2 files
© Keren Kalif
22
קריאת מספרים מקובץ וחישוב הממוצע
1.
2.
3.
4.
5.
#include <stdio.h>
void main()
{
FILE* f;
int num, sum=0, counter=0, rc;
6.
7.
8.
f = fopen("numbers.txt", "r");
// check if open succeed...
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
rc = fscanf(f, "%d", &num);
while (rc != EOF) //OR: (!feof(f))
{
printf("The read numbers is %d\n", num);
sum += num;
counter++;
rc = fscanf(f, "%d", &num);
}
fclose(f);
printf("The average is %f\n", (float)sum/counter);
20. }
© Keren Kalif
23
שמירת וטעינת מבנים לקובץ טקסט
כאשר כותבים מבנה לתוך קובץ טקסט ,יש לכתוב שדה-שדה
כאשר קוראים מבנה מקובץ טקסט ,יש לקרוא שדה-שדה
24
© Keren Kalif
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
#define SIZE 20
struct Person
{
char name[SIZE];
long id;
float age;
} typedef person_t;
שמירת וטעינת מבנים
דוגמא- מקובץ טקסט
void main()
{
person_t p1={"momo", 1111, 23.5}, p2 = {"gogo", 2222, 24.8}, p3, p4;
FILE* f = fopen("persons.txt", "w");
fprintf(f, "%s %ld %.2f\n", p1.name, p1.id, p1.age);
fprintf(f, "%s %ld %.2f\n", p2.name, p2.id, p2.age);
fclose(f);
15.
16.
17.
18.
19.
20.
21. }
f = fopen("persons.txt", "r");
fscanf(f, "%s %ld %f\n", p3.name, &p3.id, &p3.age);
fscanf(f, "%s %ld %f\n", p4.name, &p4.id, &p4.age);
fclose(f);
printf("p3: name: %s\t id: %ld\t age: %.2f\n", p3.name, p3.id, p3.age);
printf("p4: name: %s\t id: %ld\t age: %.2f\n", p4.name, p4.id, p4.age);
© Keren Kalif
25
שמירה וטעינת מערך של מבנים מקובץ טקסט
כאשר כותבים מערך לקובץ ,השדה הראשון צריך להיות מספר
המבנים שאנו כותבים ,כדי שקורא הקובץ ידע כמה מבנים יש
בתוכו
26
© Keren Kalif
1.
2.
3.
4.
5.
6.
struct Person
{
char name[SIZE];
long id;
float age;
} typedef person_t;
– שמירה וטעינה
)1( מערך מבנים
7.
8.
9.
10.
11.
12.
13.
14.
void main()
{
FILE* f;
person_t* personsSource, *personsDest;
int sizeSource, sizeDest, i;
printf("How many persons? ");
scanf("%d", &sizeSource);
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
// allocating the persons array
personsSource = (person_t*)malloc(sizeSource*sizeof(person_t));
// reading persons..
for (i=0 ; i < sizeSource ; i++)
{
printf("Enter name, id and age of person #%d: ", i+1);
scanf("%s %ld %f", personsSource[i].name, &personsSource[i].id,
&personsSource[i].age);
© Keren Kalif
}
27
24.
25.
26.
27.
28.
..המשך
f = fopen("persons.txt", "w");
fprintf(f, "%d\n", sizeSource); // writing the size to the file
for (i=0 ; i < sizeSource ; i++) // writing each person to the file
fprintf(f, "%s %ld %f\n", personsSource[i].name, personsSource[i].id, personsSource[i].age);
fclose(f);
29.
30.
free(personsSource); // don’t forget to free the array!!
31.
32.
33.
34.
35.
36.
37.
38.
39.
f = fopen("persons.txt", "r");
fscanf(f, "%d\n", &sizeDest); // reading the size from the file
// allocating the new array
personsDest = (person_t*)malloc(sizeDest*sizeof(person_t));
// reading each person from the file
for (i=0 ; i < sizeDest ; i++)
fscanf(f, "%s %ld %f\n", personsDest[i].name, &personsDest[i].id, &personsDest[i].age);
fclose(f);
40.
41.
42.
43.
44.
printf("There are %d persons in the file:\n", sizeDest);
for (i=0 ; i < sizeDest ; i++)
printf("Person #%d: Name=%s\t Id=%ld\t Age=%f\n", i+1,
personsDest[i].name, personsDest[i].id, personsDest[i].age);
45.
46.
47. }
free(personsDest); // don’t forget to free the array!!
© Keren Kalif
28
כתיבה לקובץ בינארי
פקודת הכתיבה לקובץ בינארי:
int fwrite(const void * ptr, // address of variable to write
// size of type
// number of elements
// pointer to the file
int size,
int count,
; (FILE * stream
מחזירה את כמות האיברים שכתבה
כאשר כותבים לקובץ בינארי ניתן לכתוב בלוק של מידע
למשל :מערך או מבנה בפעולת כתיבה בודדת
יש להיזהר מכתיבת פוינטרים לקובץ!
29
© Keren Kalif
קריאה מקובץ בינארי
פקודת הקריאה מקובץ בינארי:
// address of variable to read into
int fread(void* ptr,
int size,
// size of type
int count,
// number of elements
FILE* stream( ; // pointer to the file
מחזירה את כמות האיברים שקראה
כאשר קוראים מקובץ בינארי ניתן לקרוא בלוק של מידע
למשל :מערך או מבנה בפעולת קריאה בודדת
30
© Keren Kalif
1.
2.
3.
4.
5.
6.
7.
#define SIZE 20
struct Person
{
char name[SIZE];
long id;
float age;
} typedef person_t;
שמירת וטעינת מבנים
דוגמא- מקובץ בינארי
8.
9.
10.
11.
12.
13.
14.
15.
void main()
{
person_t p1={"momo", 1111, 23.5}, p2 = {"gogo", 2222, 24.8}, p3, p4;
FILE* f = fopen("persons.bin", "wb");
fwrite(&p1, sizeof(person_t), 1, f);
fwrite(&p2, sizeof(person_t), 1, f);
!רשומה בפעולה אחת
fclose(f);
ניתן לקרוא ולכתוב
16.
17.
18.
19.
20.
f = fopen("persons.bin", "rb");
fread(&p3, sizeof(person_t), 1, f);
fread(&p4, sizeof(person_t), 1, f);
fclose(f);
21.
22.
23.
printf("p3: name: %s\t id: %ld\t age: %.2f\n", p3.name, p3.id, p3.age);
printf("p4: name: %s\t id: %ld\t age: %.2f\n", p4.name, p4.id, p4.age);
24. }
© Keren Kalif
31
1.
2.
3.
4.
5.
6.
7.
#define SIZE 20
struct Person
{
char name[SIZE];
long id;
float age;
} typedef person_t;
שמירה וטעינה מערך מבנים
מקובץ בינארי
8.
9.
10.
11.
12.
13.
14.
15.
void main()
{
FILE* f;
person_t* personsSource, *personsDest;
int sizeSource, sizeDest, i;
printf("How many persons? ");
scanf("%d", &sizeSource);
16.
17.
18.
19.
20.
21.
22.
23.
24.
// allocating the persons array
personsSource = (person_t*)malloc(sizeSource*sizeof(person_t));
for (i=0 ; i < sizeSource ; i++) // reading persons..
{
printf("Enter name, id and age of person #%d: ", i+1);
scanf("%s %ld %f", personsSource[i].name,
&personsSource[i].id, &personsSource[i].age);
}
© Keren Kalif
32
25.
26.
27.
28.
29.
30.
f = fopen("persons.bin", "wb");
fwrite(&sizeSource, sizeof(int), 1, f); // writing the size to the file
// writing all persons to the file
fwrite(personsSource, sizeof(person_t), sizeSource, f);
fclose(f);
free(personsSource); // don’t forget to free the array!!
..המשך
31.
32.
33.
34.
35.
36.
37.
38.
39.
f = fopen("persons.bin", "rb");
// reading the size from the file
fread(&sizeDest, sizeof(int), 1, f);
// allocating the new array
personsDest = (person_t*)malloc(sizeDest*sizeof(person_t));
// reading all persons from the file
fread(personsDest, sizeof(person_t), sizeDest, f);
fclose(f);
40.
41.
42.
43.
44.
printf("There are %d persons in the file:\n", sizeDest);
for (i=0 ; i < sizeDest ; i++)
printf("Person #%d: Name=%s\t Id=%ld\t Age=%f\n",
i+1, personsDest[i].name, personsDest[i].id, personsDest[i].age);
45.
46.
47.
48. }
// don’t forget to free the array!!
free(personsDest);
© Keren Kalif
33
כתיבת מבנים המכילים מצביעים
יש לשים לב לא לכתוב מצביעים לתוך קובץ ,שכן אין הבטחה
שבפעם הבאה שהתוכנית תרוץ יהיו ערכים בכתובות הנוכחיות
שאנו שומרים
לכן ,כאשר יש משתנה שהוא כתובת יש להקפיד לרשום את ערכו
לקובץ
נשים לב :לא נוכל להשתמש בשיטה של לרשום מבנה ע"י ,fwrite
אלא נהיה חייבים לכתוב את המבנה לקובץ שדה-שדה
בד"כ אם המצביע הוא למערך ,נרשום כשדה נוסף את כמות
האלמנטים במערך ,ורק אח"כ את איבריו (כנ"ל עבור מחרוזת).
34
© Keren Kalif
דוגמא – שמירה וטעינה של מבנה עם מצביעים
1.
2.
3.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
4.
5.
6.
7.
8.
struct Student
{
char* name;
float average;
} typedef student_t;
9. void main()
10. {
11.
student_t stud1 = {"yoyo", 91.8}, stud2;
12.
FILE* f = fopen("students.bin", "wb");
13.
int len1, len2;
14.
// check open succeed...
15.
16.
len1 = strlen(stud1.name)+1;
17.
fwrite(&len1, sizeof(int), 1, f);
18.
fwrite(stud1.name, sizeof(char), len1, f);
19.
fwrite(&stud1.average, sizeof(float), 1, f);
20.
fclose(f);
21.
22.
f = fopen("students.bin", "rb");
23.
// check open succeed...
24.
25.
fread(&len2, sizeof(int), 1, f);
26.
stud2.name = (char*)malloc(len2*sizeof(char))
27.
fread(stud2.name, sizeof(char), len2, f);
28.
fread(&stud2.average, sizeof(float), 1, f);
29.
fclose(f);
30.
printf("stud2: name=%s, average=%.2f\n",
31.
stud2.name, stud2.average);
32.
free(stud2.name);
© Keren Kalif 35
33. }
פקודה fseek
מאפשרת לטייל בקובץ בלי לקרוא חלק משדותיו
int fseek(FILE* f,
// the file
long int offset, // how much
; (int origin
// from where
origin יקבל אחד מהערכים הבאים:
– SEEK_SET לזוז מתחילת הקובץ
– SEEK_END לזוז לסוף הקובץ
– SEEK_CUR לזוז מהמיקום הנוכחי
הפונקציה תחזיר 0אם הצליחה לזוז כמתבקש
לידע כללי :יש מערכות הפעלה בהן fseekלא עובדת טוב על קבצי
טקסט
36
© Keren Kalif
דוגמא- fseek
1.
#include <stdio.h>
2.
3.
4.
5.
6.
7.
int main ()
{
FILE * f;
f = fopen("myfile.txt" , "w");
// check if open succeed
8.
9.
10.
11.
12.
fputs("This is an apple" , f);
fseek (f , 9 , SEEK_SET);
fputs(" sam" , f);
fclose(f);
13. }
© Keren Kalif
37
– דוגמא – החבר הכי טובfseek
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
#define MAX_LEN 20
typedef struct Friend
}
char name[MAX_LEN];
int numOfPresents;
} Friend;
void sortFriendByPresents(Friend friends[], int size)
}
Friend temp;
int i, j;
for (i=0 ; i < size ; i++)
}
for (j=i+1 ; j < size ; j++)
}
if (friends[i].numOfPresents > friends[j].numOfPresents)
}
temp = friends[i];
friends[i] = friends[j];
friends[j] = temp;
{
}
{
{
© Keren Kalif
38
)2( – דוגמא – החבר הכי טובfseek
1. void main()
2. }
3.
FILE* f;
4.
Friend bestFriend;
5.
Friend myFriends[] = { {"momo", 5}, {"gogo", 2}, {"yoyo", 7} };
6.
int numOfFriends = sizeof(myFriends) / sizeof(myFriends[0]);
7.
8.
sortFriendByPresents(myFriends, numOfFriends);
9.
10.
f = fopen("myFriends.bin", "wb"); // check open file succeed...
11.
fwrite(&numOfFriends, sizeof(int), 1, f);
12.
fwrite(myFriends, sizeof(Friend), numOfFriends, f);
13.
fclose(f);
14.
numOfFriends = 0; // just reset to see correct value is read from file..
15.
// get the friend that bought me most presents
16.
f = fopen("myFriends.bin", "rb"); // check open file succeed...
17.
fread(&numOfFriends, sizeof(int), 1, f);
18.
fseek(f, sizeof(Friend)*(numOfFriends-1), SEEK_CUR);
19.
//OR: fseek(f, sizeof(Friend)*(-1), SEEK_END);
20.
fread(&bestFriend, sizeof(Friend), 1, f);
21.
fclose(f);
22.
printf("The friend who bought me most presents: %s\n", bestFriend.name);
23. {
© Keren Kalif
39
ftell הפקודה
מחזירה את מרחק הסמן מתחילת הקובץ
long ftell (FILE * f);
1. #include <stdio.h>
קריאת גודל של קובץ: דוגמא
2.
3. int main ()
4. {
5.
6.
FILE* f;
long size;
7.
8.
9.
f = fopen ("myFile.txt", "r");
// check if open succeed
10.
11.
12.
13.
14.
15. }
fseek (f, 0, SEEK_END);
size = ftell(f);
fclose (f);
printf ("Size of myfile.txt: %ld bytes.\n",size);
© Keren Kalif
40
מציאת מספר המבנים בקובץ
1.
2.
3.
4.
5.
6.
#define MAX_LEN 20
typedef struct Friend
{
char name[MAX_LEN];
int numOfPresents;
} Friend;
אם יש קובץ שהנתונים בו הם ללא
כלומר הגודל של כל איבר,מצביעים
ftell - וfseek ניתן באמצעות,זהה
לדעת את כמות המבנים בקובץ
7. void main()
8. {
9.
FILE* f;
10.
Friend myFriends[] = { {"momo", 5}, {"gogo", 2}, {"yoyo", 7} };
11.
int numOfFriends = sizeof(myFriends) / sizeof(myFriends[0]);
12.
13.
f = fopen("myFriends.bin", "wb"); // check open file succeed...
14.
fwrite(myFriends, sizeof(Friend), numOfFriends, f);
15.
fclose(f);
16.
17.
18.
19.
20.
21. }
numOfFriends = 0;
f = fopen("myFriends.bin", "rb"); // check open file succeed...
fseek(f, 0, SEEK_END);
numOfFriends = ftell(f) / sizeof(Friend);
fclose(f);
© Keren Kalif
41
rewind הפקודה
void rewind(FILE* f);
1. int main ()
: מחזירה את הסמן לתחילת הקובץ
ABC - קריאת וכתיבת כל ה: דוגמא
2. {
3.
4.
5.
int n;
FILE *f;
char buffer [27];
6.
7.
8.
f = fopen ("allLetters.txt","w+");
// check if open succeed
9.
10.
11.
12.
13.
14.
15.
16.
17. }
for ( n='A' ; n<='Z' ; n++)
fputc ( n, f);
rewind (f);
fscanf(f, "%s", buffer);
fclose (f);
buffer[26]='\0';
puts (buffer);
© Keren Kalif
42
ferror הפקודה
במידה והפעולות שבוצעו על הקובץ תקינות0 פקודה זו מחזירה
כאשר ננסה לכתוב לקובץ שנפתח לקריאה בלבד: דוגמא
1. void main()
2. {
3.
FILE* f = fopen("myfile.txt","r");
4.
if (f == NULL)
5.
{
6.
printf("Error opening file\n");
7.
return;
8.
}
9.
10.
fputc('x', f);
11.
if (ferror(f))
12.
printf ("Error Writing to myfile.txt\n");
13.
fclose(f);
14. }
© Keren Kalif
43
דוגמא :ניהול קורסים וסטודנטים במכללה
דגשים לתוכנית:
שימוש בקבועים
פונקציות יעודיות להדפסה ולקבלת קלט
מודולריות
חלוקה לקבצים
יצירת פונקציה עבור לוגיקה ספציפית ,עבור תחזוקה
עתידית
למשלgetDepartmentCodeFromCourseCode :
44
© Keren Kalif
קובץ אינדקסים -מוטיבציה
בהינתן קובץ טקסט עם שורות (ניתן להניח שאורך כל שורה הוא
מקסימום 255תווים ,אבל לא בהכרח) נרצה לקרוא תו ספציפי
בשורה מסוימת
הפתרון :נקרא שורה-שורה עד השורה המבוקשת ,ובתוכה נזוז
למיקום הרצוי
דוגמא :בהינתן הקובץ הבא ,נרצה להגיע לתו ה 7 -בשורה 4
45
© Keren Kalif
הקוד
דילוג על השורות הראשונות.
לא ניתן לדלג באמצעות fseek
כי אורך השורות שונה.
כאשר הסמן נמצא בתחילת השורה
המבוקשת ,נקפוץ ישירות למיקום
התו אותו רוצים לקרוא.
46
© Keren Kalif
פעולת הקריאה מקובץ היא פעולה יקרה ולכן נרצה
מנגנון אחר שיחסוך זאת.
כלומר ,מנגנון שונה להגעה ישירה לשורה המבוקשת.
)(1. void main
{ 2.
3.
;int line, col, i
4.
;char text[256], ch
5.
;)"FILE* f = fopen("test.txt", "r
6.
7.
;)" >printf("Enter line and col --
8.
;)scanf("%d%d", &line, &col
9.
10.
)for (i=1 ; i < line ; i++
11.
;)fgets(text, 256, f
12.
13.
;)fseek(f, col-1, SEEK_CUR
14.
;)ch = fgetc(f
15.
;)printf("The char is '%c'\n", ch
16.
17.
;)fclose(f
} 18.
קובץ אינדקסים -בפתרון
כאשר רוצים לבצע קריאות רבות ונקודתיות מקובץ בעל אורך
שורות שונה שאינו משתנה ,נשתמש במנגנון הנקרא "קובץ
אינדקסים"
קובץ זה יכיל מספרים ,כאשר המספר ה i-הוא מיקום התו הראשון
בשורה ה i -בקובץ
דוגמא:
שימושים :למשל עבור ספר טלפונים (נתוניו קבועים) ,נרצה לקבל
נתונים של רשומה אחת
כל שינוי בקובץ המקורי יגרור שינוי בקובץ האינדקס
47
© Keren Kalif
קובץ האינדקס חייב להיות בינארי כדי
שלםint שבקריאה נוכל לדלג כל פעם על
יצירת קובץ אינדקס
void main(int argc, char* argv[])
{
char indexFileName[128], line[256];
FILE *textFile, *indexFile;
int currentIndex, numOfChars;
createIndexFileName(argv[1], indexFileName);
textFile = fopen(argv[1], "r");
indexFile = fopen(indexFileName, "wb");
,פתיחת קובץ הטקסט לקריאה
וקובץ האינדקס בינארי לכתיבה
fseek(textFile, 0, SEEK_END);
numOfChars = ftell(textFile);
נמצא את כמות התווים בקובץ הטקסט
fseek(textFile, 0, SEEK_SET);
currentIndex = 0;
,נמצא את מיקום הסמן בתחילת כל שורה
while (currentIndex < numOfChars)
ונכתוב ערך זה לקובץ האינדקסים
{
fwrite(¤tIndex, sizeof(int), 1, indexFile);
fgets(line, 256, textFile);
currentIndex = ftell(textFile);
}
fclose(textFile);
fclose(indexFile);
}
© Keren Kalif
48
יצירת שם קובץ האינדקס
: פונקציה זו יוצרת את שם קובץ האינדקס כך
<file name>.txt עבור קובץ
<file name>_index.bin : שם קובץ האינדקס יהיה
test_index.bin שם ובץ האינדקס יהיהtest.txt עבור: דוגמא
void createIndexFileName(const char* origName, char indexName[])
{
strcpy(indexName, origName);
strtok(indexName, ".");
strcat(indexName, "_index.bin");
}
© Keren Kalif
49
void main(int argc, char* argv[])
{
FILE *textFile, *indexFile;
int col, row, lineStartIndex;
char ch;
שימוש בקובץ אינדקס
textFile = fopen(argv[1], "r");
indexFile = fopen(argv[2], "rb");
פתיחת קובץ הטקסט וקובץ
האינדקס הבינארי לקריאה
printf("Enter row and col --> ");
scanf("%d%d", &row, &col);
fseek(indexFile, (row-1)*sizeof(int), SEEK_SET);
fread(&lineStartIndex, sizeof(int), 1, indexFile);
fseek(textFile, lineStartIndex+col-1, SEEK_SET);
fscanf(textFile, "%c", &ch);
קריאה מקובץ האינדקס את
מיקום תחילת השורה
הזזת הסמן בקובץ הטקסט
למיקום המבוקש וקריאה
printf("The char is %c\n", ch);
fclose(textFile);
fclose(indexFile);
}
© Keren Kalif
50
תרגיל :מיון ישירות בקובץ
C
:
.1הגדר את המבנה Studentהמכיל את השדות הבאים:
שם (מחרוזת סטטית עד 10תווים)
ת.ז( .מספר שלם)
ממוצע (מספר עשרוני)
.2כתוב mainהמבצע את הדברים הבאים:
.1.2הגדר 5סטודנטים וכתוב את נתוניהם לתוך קובץ.
.2.2מיין את הסטודנטים בקובץ לפי הממוצע שלהם.
הגבלה :המיון צריך להיות ישירות בתוך הקובץ ,ולא במערך בזיכרון.
.3.2קרא מהקובץ את כמות הסטודנטים שנרשמו אליו ,וקרא את הנתונים לתוך מערך חדש של סטודנטים.
.4.2הדפס את הנתונים שקראת וודא שהסטודנטים ממויינים לפי הממוצע.
51
© Keren Kalif
ביחידה זו למדנו:
מוטיבציה לעבודה עם קבצים
סוגי קבצים:
בינאריים
טקסט
פעולות על קבצים (עבור שני סוגי הקבצים):
פתיחת קובץ
קריאה מקובץ
כתיבה לקובץ
סגירת קובץ
פעולות נוספותfseek, ftell, rewind, ferror, fflush, feof :
קובץ אינדקסים
52
© Keren Kalif