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(&currentIndex, 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‬‬