דוגמא - קרן כליף

Download Report

Transcript דוגמא - קרן כליף

‫קבצים‬
‫קרן כליף‬
‫‪© Keren Kalif‬‬
‫ביחידה זו נלמד‪:‬‬
‫‪‬‬
‫‪‬‬
‫מוטיבציה לעבודה עם קבצים‬
‫סוגי קבצים‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫פעולות על קבצים (עבור שני סוגי הקבצים)‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪2‬‬
‫בינאריים‬
‫טקסט‬
‫פתיחת קובץ‬
‫קריאה מקובץ‬
‫כתיבה לקובץ‬
‫סגירת קובץ‬
‫פעולות נוספות‪fseek, ftell, rewind, ferror, fflush, feof :‬‬
‫‪© Keren Kalif‬‬
‫קבצים ‪ -‬מוטיבציה‬
‫‪‬‬
‫‪‬‬
‫כאשר אנחנו כותבים תוכנה‪ ,‬המידע אשר אנחנו מכניסים‬
‫בכל הרצה הולך לאיבוד עם סיומה‪ ,‬מאחר והתוכנה רצה‬
‫בזיכרון ה‪ RAM -‬של המחשב‬
‫היינו רוצים לשמור את המידע בין ההרצות בזיכרון הקבוע‬
‫(‪ )Hard Disk‬כדי‪:‬‬
‫‪ ‬ליצור תוכנה בעלת משמעות ורצף‬
‫‪ ‬להקל עלינו בעת בדיקות התוכנה‬
‫‪‬‬
‫‪‬‬
‫‪3‬‬
‫קריאת נתונים מקובץ מוכן מראש ולא מהמשתמש‬
‫‪ ‬שמירת נתונים לשימוש ע"י תוכניות אחרות‬
‫ניתן לשמור את המידע בכמה אופנים שונים‪:‬‬
‫‪( DB ‬לא יילמד בקורס זה)‬
‫‪ ‬קבצים‬
‫‪© Keren Kalif‬‬
‫עבודה כללית עם קבצים ‪ -‬מוטיבציה‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪4‬‬
‫יתכן ותהייה לנו תוכנית שנרצה לשמור את הפלט שלה‬
‫לקובץ‬
‫יתכן ותהייה לנו תוכנית שנרצה שהקלט שלה יהיה מקובץ‪,‬‬
‫ולא מהמקלדת‬
‫דוגמא‪:‬‬
‫‪ ‬קריאת אוסף מספרים מקובץ בפורמט ידוע מראש‬
‫והצגת סכום המספרים‬
‫‪ ‬כתיבת תוכנית המכינה דו"ח כלשהו ושומרת את הדוח‬
‫בקובץ‪ ,‬בנוסף להצגתו על המסך‬
‫‪© Keren Kalif‬‬
‫סוגי קבצים‬
‫‪5‬‬
‫‪‬‬
‫קובץ טקסט‪:‬‬
‫‪ ‬כתוב בשפה אותה אנו יכולים לקרוא ולהבין‬
‫‪‬‬
‫קובץ בינארי‪:‬‬
‫‪ ‬לא ניתן להבין את התוכן‬
‫‪© Keren Kalif‬‬
‫מבנה עבודה כללי עם קבצים‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫קובץ הוא משתנה מטיפוס *‪ FILE‬ומוגדר ב‪stdio.h -‬‬
‫בתחילת העבודה יש לפתוח קובץ לקריאה‪/‬לכתיבה תוך ציון‬
‫האם זהו קובץ טקסט או בינארי‬
‫יש לבדוק האם פתיחה הצליחה‬
‫לבסוף יש לסגור את הקובץ‬
‫)(‪void main‬‬
‫{‬
‫;)>‪FILE* f = fopen(<file name>, <open parameters‬‬
‫)‪if (f == NULL‬‬
‫{‬
‫;)"‪printf("Failed opening the file. Exiting!\n‬‬
‫;‪return‬‬
‫}‬
‫‪// here some operation with the file..‬‬
‫;)‪fclose(f‬‬
‫}‬
‫‪6‬‬
‫‪1.‬‬
‫‪2.‬‬
‫‪3.‬‬
‫‪4.‬‬
‫‪5.‬‬
‫‪6.‬‬
‫‪7.‬‬
‫‪8.‬‬
‫‪9.‬‬
‫‪10.‬‬
‫‪11.‬‬
‫‪© Keren Kalif‬‬
‫פתיחת קובץ – פרמטרים לסוג הפתיחה‬
‫‪‬‬
‫‪‬‬
‫;)‪FILE* fopen(char* fileName, char* mode‬‬
‫פתיחת קובץ טקסט לקריאה‪“r” :‬‬
‫פתיחת קובץ טקסט לכתיבה‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫פתיחת קובץ טקסט לקריאה ולכתיבה‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫”‪ – “r+‬הקובץ חייב להיות קיים‪ ,‬יתקבל ‪ NULL‬אם לא‬
‫”‪ – “w+‬אם הקובץ קיים‪ ,‬דורס אותו‬
‫”‪ – “a+‬אם הקובץ קיים כותב לסופו‪ ,‬אחרת יוצר קובץ חדש‪ .‬לא מאפשר‬
‫כתיבה לתחילת הקובץ!‬
‫כדי לפתוח את הקובץ כבינארי נוסיף ‪ b‬בסוף הפרמטר לפתיחה‪.‬‬
‫למשל‪ “rb”, “wb” :‬וכו'‪ .‬ברירת המחדל היא קובץ טקסט‪.‬‬
‫‪‬‬
‫‪7‬‬
‫”‪ - “w‬במידה ויש נתונים בקובץ הם ידרסו‬
‫”‪ – “a‬כותב לסוף קובץ (כלומר לא דורס את המידע‪ ,‬אם קיים)‪ .‬לא מאפשר‬
‫כתיבה לתחילת הקובץ!‬
‫ניתן ב‪ mode -‬הפתיחה לציין ‪ ,t‬עבור קובץ טקסט‪ .‬למשל‪“wt” :‬‬
‫‪© Keren Kalif‬‬
‫פתיחת קובץ – סיבות לכשלון‬
‫‪8‬‬
‫‪‬‬
‫קובץ המוגדר לקריאה בלבד שמנסים לפתוח אותו לכתיבה‬
‫‪‬‬
‫פתיחה ע"י "‪ "r‬קובץ שאינו קיים‬
‫‪© Keren Kalif‬‬
‫סגירת קובץ‬
‫‪‬‬
‫;)‪ int fclose(FILE* file‬‬
‫מקבלת מצביע לקובץ ומחזירה ‪ 0‬אם הצליחה לסגור אותו‪,‬‬
‫אחרת תחזיר ‪( -1‬הקבוע ‪)EOF‬‬
‫‪‬‬
‫‪‬‬
‫‪9‬‬
‫תכשל למשל כאשר מנסים לסגור קובץ שאינו פתוח‬
‫;)(‪ int fcloseall‬‬
‫סוגרת את כל הקבצים שפתחנו ומחזירה את מספר הקבצים‬
‫שסגרה‬
‫‪© Keren Kalif‬‬
‫כתיבה לקובץ טקסט‬
‫‪ ‬פקודות הכתיבה לקובץ טקסט הן כמו הפקודות‬
‫לכתיבה למסך‪ ,‬פרט לכך ש‪:‬‬
‫‪‬‬
‫‪‬‬
‫שמן מתחיל עם ‪f‬‬
‫הן מקבלות פרמטר נוסף שהוא מצביע לקובץ אליו רוצים‬
‫לכתוב‬
‫;) ‪int fprintf(FILE* , char*, ...‬‬
‫;)*‪ int fputs(char*, FILE‬‬
‫;)*‪ int fputc(char, FILE‬‬
‫‪‬‬
‫‪10‬‬
© 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);
}
11
© Keren Kalif
)2( ‫כתיבה לקובץ טקסט – דוגמא‬
1.
#include <stdio.h>
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
void main()
{
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.
f = fopen("myFile.txt", "a");
fputs("And Good Morning!\n", f);
fclose(f);
15.
16.
17.
18.
‫פתיחת הקובץ וכתיבה לסופו‬
}
12
© Keren Kalif
)3( ‫כתיבה לקובץ טקסט – דוגמא‬
1.
#include <stdio.h>
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
void main()
{
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.
f = fopen)"myFile.txt", “w");
fputs("And Good Morning!\n", f);
fclose(f);
15.
16.
17.
18.
}
13
‫‪© Keren Kalif‬‬
‫קריאה מקובץ טקסט‬
‫‪‬‬
‫פקודות הקריאה לקובץ טקסט הן כמו הפקודות הקריאה‬
‫למסך‪ ,‬פרט לכך ש‪:‬‬
‫‪‬‬
‫‪‬‬
‫שמן מתחיל עם ‪f‬‬
‫הן מקבלות פרמטר נוסף שהוא מצביע לקובץ אליו רוצים לכתוב‬
‫מקבלות גם את כמות התווים לקריאה‪.‬‬
‫קוראת עד ’‪ ‘\n‬או עד ‪ n-1‬תווים‬
‫;) ‪int fscanf(FILE* , char*, ...‬‬
‫;)*‪char* fgets(char*, int n, FILE‬‬
‫‪‬‬
‫‪‬‬
‫מחזירה את המחרוזת שקראה או ‪ NULL‬אם לא הצליחה (למשל‬
‫הקובץ נגמר)‬
‫;)*‪int fgetc(FILE‬‬
‫‪‬‬
‫מחזירה את ערך האסקיי של התו או את הקבוע ‪( EOF‬שערכו ‪ )-1‬אם‬
‫לא הצליחה (למשל הקובץ נגמר)‬
‫‪14‬‬
‫‪© Keren Kalif‬‬
‫שמירה וקריאה מקובץ ‪ -‬כללי‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪15‬‬
‫כאשר נשמור מידע לקובץ‪ ,‬אנו בוחרים לשמור את המידע‬
‫בסדר מסוים‬
‫צריכה להיות התאמה בין סדר כתיבת הנתונים לקובץ לסדר‬
‫קריאת הנתונים מהקובץ‬
‫למשל‪ :‬אם כתבתי מידע על סטודנט בסדר הבא‪ :‬שם ‪ ,‬ת‪.‬ז‪.‬‬
‫וגיל‪ ,‬גם סדר קריאת הנתונים יהיה זהה‬
‫כלומר‪ ,‬צריכה להיות הסכמה וידיעה בין מי שכותב לקובץ ומי‬
‫שקורא ממנו לגבי סדר הנתונים בקובץ‬
© Keren Kalif
‫קריאה מקובץ טקסט – דוגמא‬
1.
2.
3.
4.
5.
6.
7.
8.
#define SIZE 20
void main()
{
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.
fputs(sentence, f);
fprintf(f, "\n%d %f %s\n", num1, f1, str);
fclose(f);
10.
11.
12.
13.
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..
14.
15.
16.
17.
fgets(sentence2, SIZE, f);
fscanf(f, "%d %f %s", &num2, &f2, str2);
18.
19.
20.
printf("\nAfter reading from file:\nnum2=%d f2=%f str=|%s| sentence2=|%s|\n", num2, f2, str2, sentence2);
fclose(f);
21.
22.
23.
}
16
‫‪© Keren Kalif‬‬
‫‪feof‬‬
‫;)‪int feof (FILE * stream‬‬
‫‪‬‬
‫‪17‬‬
‫פונקציה זו מקבלת קובץ פתוח ומחזירה ‪ 0‬אם לא הגענו לסוף‬
‫הקובץ‪ ,‬ו‪ )EOF( -1 -‬במידה והגענו לסוף‬
‫‪‬‬
© Keren Kalif
‫דוגמא – העתקת קובץ‬
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
void main()
{
char ch;
FILE* fSource, *fDest;
fSource = fopen("example.txt", "r");
// check if open file succeeded..
fDest = fopen("exampleCopy.txt", "w");
// check if open file succeeded..
ch = fgetc(fSource);
while (!feof(fSource)) // OR: (ch != EOF)
{
fputc(ch, fDest);
ch = fgetc(fSource);
}
fclose(fSource); // returns 0 since close file succeed
fclose(fDest); // returns 0 since close file succeed
}
fcloseall(); // returns 2
since closed 2 files
18
© Keren Kalif
‫קריאת מספרים מקובץ וחישוב הממוצע‬
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
#include <stdio.h>
void main()
{
FILE* f;
int num, sum=0, counter=0, rc;
f = fopen("numbers.txt", "r");
// check if open succeed...
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);
}
19
‫‪© Keren Kalif‬‬
‫שמירת וטעינת רשומות לקובץ טקסט‬
‫‪20‬‬
‫‪‬‬
‫כאשר כותבים רשומה לתוך קובץ טקסט‪ ,‬יש לכתוב שדה‪-‬שדה‬
‫‪‬‬
‫כאשר קוראים רשומה מקובץ טקסט‪ ,‬יש לקרוא שדה‪-‬שדה‬
© 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);
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);
15.
16.
17.
18.
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);
19.
20.
21.
}
21
‫‪© Keren Kalif‬‬
‫שמירה וטעינת מערך של רשומות מקובץ טקסט‬
‫‪‬‬
‫‪22‬‬
‫כאשר כותבים מערך לקובץ‪ ,‬השדה הראשון צריך להיות מספר‬
‫הרשומות שאנו כותבים‪ ,‬כדי שקורא הקובץ ידע כמה רשומות‬
‫יש בתוכו‬
© Keren Kalif
)1( ‫ מערך רשומות‬- ‫שמירה וטעינה‬
1.
2.
3.
4.
5.
6.
struct Person
{
char name[SIZE];
long id;
float age;
} typedef person_t;
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.
// 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);
}
16.
17.
18.
19.
20.
21.
22.
23.
24.
}
23
© Keren Kalif
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!!
24
‫‪© Keren Kalif‬‬
‫כתיבה לקובץ בינארי‬
‫‪‬‬
‫פקודת הכתיבה לקובץ בינארי‪:‬‬
‫‪int fwrite(const void * ptr, // address of variable to write‬‬
‫‪int size,‬‬
‫‪// size of type‬‬
‫‪int count,‬‬
‫‪// number of elements‬‬
‫‪FILE * stream( ; // pointer to the file‬‬
‫‪ ‬מחזירה את כמות האיברים שכתבה‬
‫‪‬‬
‫כאשר כותבים לקובץ בינארי ניתן לכתוב בלוק של מידע‬
‫‪‬‬
‫‪‬‬
‫‪25‬‬
‫למשל‪ :‬מערך או רשומה בפעולת כתיבה בודדת‬
‫יש להיזהר מכתיבת פוינטרים לקובץ!‬
‫‪‬‬
‫‪© Keren Kalif‬‬
‫קריאה מקובץ בינארי‬
‫‪‬‬
‫פקודת הקריאה מקובץ בינארי‪:‬‬
‫‪int fread(void* ptr,‬‬
‫‪// address of variable to read into‬‬
‫‪int size,‬‬
‫‪// size of type‬‬
‫‪int count,‬‬
‫‪// number of elements‬‬
‫‪FILE* stream( ; // pointer to the file‬‬
‫‪‬‬
‫‪‬‬
‫מחזירה את כמות האיברים שקראה‬
‫כאשר קוראים מקובץ בינארי ניתן לקרוא בלוק של מידע‬
‫‪‬‬
‫‪26‬‬
‫למשל‪ :‬מערך או רשומה בפעולת קריאה בודדת‬
‫‪‬‬
© 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.
f = fopen("persons.bin", "rb");
fread(&p3, sizeof(person_t), 1, f);
fread(&p4, sizeof(person_t), 1, f);
fclose(f);
17.
18.
19.
20.
21.
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);
22.
23.
24.
}
27
© Keren Kalif
‫שמירה וטעינה מערך רשומות‬
)1( ‫מקובץ בינארי‬
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);
}
28
© Keren Kalif
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);
29
‫‪© Keren Kalif‬‬
‫כתיבת רשומות המכילות מצביעים‬
‫‪‬‬
‫‪‬‬
‫יש לשים לב לא לכתוב מצביעים לתוך קובץ‪ ,‬שכן אין הבטחה‬
‫שבפעם הבאה שהתוכנית תרוץ יהיו ערכים בכתובות הנוכחיות‬
‫שאנו שומרים‬
‫לכן‪ ,‬כאשר יש משתנה שהוא כתובת יש להקפיד לרשום את‬
‫ערכו לקובץ‬
‫‪‬‬
‫‪‬‬
‫‪30‬‬
‫נשים לב‪ :‬לא נוכל להשתמש בשיטה של לרשום רשומה ע"י ‪,fwrite‬‬
‫אלא נהיה חייבים לכתוב את הרשומה לקובץ שדה‪-‬שדה‬
‫בד"כ אם המצביע הוא למערך‪ ,‬נרשום כשדה נוסף את כמות‬
‫האלמנטים במערך‪ ,‬ורק אח"כ את איבריו (כנ"ל עבור מחרוזת)‪.‬‬
© Keren Kalif
‫דוגמא – שמירה‬
‫וטעינה של רשומה עם‬
‫מצביעים‬
1.
2.
3.
4.
5.
6.
7.
8.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
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);
33. }
31
‫‪© Keren Kalif‬‬
‫פקודה ‪fseek‬‬
‫‪‬‬
‫‪‬‬
‫מאפשר לטייל בקובץ בלי לקרוא חלק משדותיו‬
‫‪int fseek(FILE* f,‬‬
‫‪// the file‬‬
‫‪long int offset, // how much‬‬
‫; (‪int origin‬‬
‫‪// from where‬‬
‫‪ origin‬יקבל אחד מהערכים הבאים‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪32‬‬
‫‪ – SEEK_SET‬לזוז מתחילת הקובץ‬
‫‪ – SEEK_END‬לזוז לסוף הקובץ‬
‫‪ – SEEK_CUR‬לזוז מהמיקום הנוכחי‬
‫הפונקציה תחזיר ‪ 0‬אם הצליחה לזוז כמתבקש‬
‫לידע כללי‪ :‬יש מערכות הפעלה בהן ‪ fseek‬לא עובדת טוב על‬
‫קבצי טקסט‬
© 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.
fputs("This is an apple" , f);
fseek (f , 9 , SEEK_SET);
fputs(" sam" , f);
fclose(f);
9.
10.
11.
12.
13.
}
33
© Keren Kalif
‫ – דוגמא – החבר הכי טוב‬fseek
1.
#define MAX_LEN 20
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
typedef struct Friend
}
char name[MAX_LEN];
int numOfPresentsBoughtMe;
} 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].numOfPresentsBoughtMe > friends[j].numOfPresentsBoughtMe)
}
temp = friends[i];
friends[i] = friends[j];
friends[j] = temp;
{
}
{
34
© Keren Kalif
)2( ‫ – דוגמא – החבר הכי טוב‬fseek
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
void main()
}
FILE* f;
Friend bestFriend;
Friend myFriends[] = { {"momo", 5}, {"gogo", 2}, {"yoyo", 7} };
int numOfFriends = sizeof(myFriends) / sizeof(myFriends[0]);
sortFriendByPresents(myFriends, numOfFriends);
{
f = fopen("myFriends.bin", "wb"); // check open file succeed...
fwrite(&numOfFriends, sizeof(int), 1, f);
fwrite(myFriends, sizeof(Friend), numOfFriends, f);
fclose(f);
numOfFriends = 0; // just reset to see correct value is read from file..
// get the friend that bought me most presents
f = fopen("myFriends.bin", "rb"); // check open file succeed...
fread(&numOfFriends, sizeof(int), 1, f);
fseek(f, sizeof(Friend)*(numOfFriends-1), SEEK_CUR);
//OR: fseek(f, sizeof(Friend)*-1, SEEK_END);
fread(&bestFriend, sizeof(Friend), 1, f);
fclose(f);
printf("The friend who bought me most presents: %s\n", bestFriend.name);
35
© Keren Kalif
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);
36
© Keren Kalif
rewind ‫הפקודה‬
void rewind(FILE* f);
1. int main ()
2. {
3.
4.
5.
:‫מחזירה את הסמן לתחילת הקובץ‬
ABC -‫ קריאת וכתיבת כל ה‬:‫דוגמא‬


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);
37
‫‪© Keren Kalif‬‬
‫הפקודה ‪fflush‬‬
‫)‪int fflush(FILE* f‬‬
‫‪‬‬
‫מרוקנת את ה‪ buffer -‬של הקובץ‪ .‬בדיוק כמו שמנקים את ה‪-‬‬
‫‪ buffer‬מהמקלדת ע"י )‪ .fflsh(stdin‬מחזירה ‪ 0‬אם הצליחה‪.‬‬
‫)(‪int fflush‬‬
‫‪‬‬
‫‪38‬‬
‫‪‬‬
‫מרוקנת את ה‪'buffer -‬ים של כל ה‪ stream -‬הפתוחים‬
‫(קבצים‪ stdin ,‬וכד')‪ .‬מחזירה ‪ 0‬אם הצליחה‪.‬‬
‫‪‬‬
© Keren Kalif
ferror ‫הפקודה‬
‫ במידה והפעולות שבוצעו על הקובץ תקינות‬0 ‫פקודה זו מחזירה‬
‫ כאשר ננסה לכתוב לקובץ שנפתח לקריאה בלבד‬:‫דוגמא‬
1.
2.
3.
4.
5.
6.
7.
8.


void main()
{
FILE* f = fopen("myfile.txt","r");
if (f == NULL)
{
printf("Error opening file\n");
return;
}
9.
fputc('x', f);
if (ferror(f))
printf ("Error Writing to myfile.txt\n");
fclose(f);
10.
11.
12.
13.
14.
}
39
‫‪© Keren Kalif‬‬
‫דוגמא‪ :‬ניהול קורסים וסטודנטים במכללה‬
‫‪‬‬
‫‪40‬‬
‫דגשים לתוכנית‪:‬‬
‫‪ ‬שימוש בקבועים‬
‫‪ ‬פונקציות יעודיות להדפסה ולקבלת קלט‬
‫‪ ‬מודולריות‬
‫‪ ‬חלוקה לקבצים‬
‫‪ ‬יצירת פונקציה עבור לוגיקה ספציפית‪ ,‬עבור תחזוקה‬
‫עתידית‬
‫‪ ‬למשל‪getDepartmentCodeFromCourseCode :‬‬
‫‪© Keren Kalif‬‬
‫קובץ אינדקסים ‪ -‬מוטיבציה‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪41‬‬
‫בהינתן קובץ טקסט עם שורות (ניתן להניח שאורך כל שורה‬
‫הוא מקסימום ‪ 255‬תווים‪ ,‬אבל לא בהכרח) נרצה לקרוא תו‬
‫ספציפי בשורה מסוימת‬
‫הפתרון‪ :‬נקרא שורה‪-‬שורה עד השורה המבוקשת‪ ,‬ובתוכה נזוז‬
‫למיקום הרצוי‬
‫דוגמא‪ :‬בהינתן הקובץ הבא‪ ,‬נרצה להגיע לתו ה‪ 7 -‬בשורה ‪4‬‬
‫‪© Keren Kalif‬‬
‫הקוד‬
‫דילוג על השורות הראשונות‪.‬‬
‫לא ניתן לדלג באמצעות ‪fseek‬‬
‫כי אורך השורות שונה‪.‬‬
‫כאשר הסמן נמצא בתחילת השורה‬
‫המבוקשת‪ ,‬נקפוץ ישירות למיקום‬
‫התו אותו רוצים לקרוא‪.‬‬
‫‪42‬‬
‫פעולת הקריאה מקובץ היא פעולה יקרה ולכן נרצה‬
‫מנגנון אחר שיחסוך זאת‪.‬‬
‫כלומר‪ ,‬מנגנון שונה להגעה ישירה לשורה המבוקשת‪.‬‬
‫)(‪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.‬‬
‫‪© Keren Kalif‬‬
‫קובץ אינדקסים ‪ -‬בפתרון‬
‫‪‬‬
‫כאשר רוצים לבצע קריאות רבות ונקודתיות מקובץ בעל אורך שורות‬
‫שונה שאינו משתנה‪ ,‬נשתמש במנגנון הנקרא "קובץ אינדקסים"‬
‫קובץ זה יכיל מספרים‪ ,‬כאשר המספר ה‪ i-‬הוא מיקום התו הראשון‬
‫בשורה ה‪ i -‬בקובץ‬
‫דוגמא‪:‬‬
‫‪‬‬
‫שימושים‪ :‬למשל עבור ספר טלפונים (נתוניו קבועים)‪ ,‬נרצה לקבל‬
‫נתונים של רשומה אחת‬
‫כל שינוי בקובץ המקורי יגרור שינוי בקובץ האינדקס‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪43‬‬
© Keren Kalif
‫יצירת קובץ אינדקס‬
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);
}
‫קובץ האינדקס חייב להיות בינארי כדי‬
‫ שלם‬int ‫שבקריאה נוכל לדלג כל פעם על‬
44
© Keren Kalif
‫יצירת שם קובץ האינדקס‬
:‫פונקציה זו יוצרת את שם קובץ האינדקס כך‬
<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");
}
45
© Keren Kalif
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);
}
46
‫‪© Keren Kalif‬‬
‫דוגמאת סיכום‪ :‬קבצים‪ ,‬סיביות‪variadic functions ,‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫כתוב פונקציה המקבלת שם של קובץ בינארי וכמות כלשהי של‬
‫מספרים‪ ,‬שנתון שסכומם הוא ‪( 8‬המספר האחרון יהיה ‪ ,0‬ליצוג סיום‬
‫הפרמטרים)‬
‫כל מספר מייצג כמות סיביות המייצגות מספר‪.‬‬
‫יש לקרוא את הקובץ הבינארי ולהציג את המספרים המקודדים‬
‫בתוכו‪.‬‬
‫למשל‪ ,‬עבור המספרים ‪ 4,1,3‬והבתים הבאים שנקראו מהזכרון‬
‫(‪:)abc‬‬
‫‪01100001 01100010 01100011‬‬
‫יודפסו למסך המספרים הבאים‪:‬‬
‫‪47‬‬
© Keren Kalif
1.
2.
3.
4.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
5.
6.
7.
8.
unsigned char createMask(int high, int low);
int getSubNumber(char ch, unsigned char mask, int high, int low);
void readNumbers(const char* fileName, ...);
9.
10.
11.
12.
13.
14.
15.
void main()
{
char str[] = "abc"; // a: 01100001 b: 01100010 c: 01100011
FILE* f = fopen("test.bin", "wb");
fwrite(str, sizeof(char), strlen(str), f);
fclose(f);
16.
readNumbers("test.bin", 4, 1, 3, 0);
17.
18.
{
48
© Keren Kalif
!‫מוזמנים לקרוא את ההסבר לפונקציה זו בדפים שבאתר‬
/* This function receives higher and lower bounds of bit indexes,
and creates a mask with 1 in this range, and 0 in all other
places.
I.E: high=5, low=3, the mask char would be: 00111000
*/
19. unsigned char createMask(int high, int low)
20. {
21.
return ( 1 << ( high + 1 ) ) - ( 1 << low );
22. {
64
8
1000000
1000
00111000
1 >> 6
1 >> 3
64-8=56
49
© Keren Kalif
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
void readNumbers(const char* fileName, ...)
{
FILE* f;
va_list numbers;
int highBit, lowBit, i, numOfNumbers=0, arr[8];
unsigned char ch;
unsigned char* masks;
f = fopen(fileName, "rb");
if (f == NULL)
exit(1);
// get the numbers
va_start(numbers, fileName);
arr[numOfNumbers] = va_arg(numbers, int);
while (arr[numOfNumbers] != 0)
}
numOfNumbers++;
arr[numOfNumbers] = va_arg(numbers, int);
{
// allocate the masks array
masks = (char*)malloc(numOfNumbers*sizeof(unsigned char));
50
© Keren Kalif
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
{
// creates the masks
highBit=7;
for (i=0 ; i < numOfNumbers ; i++)
}
lowBit = highBit - arr[i] + 1;
masks[i] = createMask(highBit, lowBit);
highBit = lowBit - 1;
}
while (1)
}
fread(&ch, sizeof(char), 1, f);
if (feof(f))
break;
printf("From char '%c' --> ", ch);
highBit=7;
for (i=0 ; i < numOfNumbers ; i++)
{
lowBit = highBit - arr[i] + 1;
printf("%d ", ((ch & masks[i]) >> lowBit));
highBit = lowBit - 1;
}
printf("\n");
{
fclose(f);
free(masks);
51
‫‪© Keren Kalif‬‬
‫דוגמא‪ :‬יצירת קובץ בינארי המכיל קידוד תמונה‬
‫‪‬‬
‫יש לייצר קובץ בינארי המכיל יצוג של תמונה‪.‬‬
‫תמונה מורכבת מ‪ N*M -‬פיקסלים‪ ,‬כך שלכל פיקסל יש צבע‬
‫(יש ‪ 16‬צבעים אפשריים)‪.‬‬
‫יש לכתוב לקובץ את מימדי התמונה ואח"כ את כל הפיקסלים‬
‫לפי הסדר‪ :‬הפיקסלים מהשורה הראשונה‪ ,‬השניה וכו'‪.‬‬
‫‪‬‬
‫על מנת לשמור כל צבע‪ ,‬ניתן להסתפק ב‪ 4 -‬סיביות‬
‫‪‬‬
‫בכל ‪ byte‬ניתן לשמור נתונים עבור ‪ 2‬פיקסלים‬
‫‪‬‬
‫‪‬‬
‫‪ 2‬בתים בהתחלה לשמירת מימדי התמונה‬
‫‪‬‬
‫‪52‬‬
‫תמונה עם ‪ N*M‬פיקסלים תשמר ב‪ N*M/2 + 2 -‬בתים‬
‫‪© Keren Kalif‬‬
‫דוגמא ‪ :2‬שינוי צבע לפיקסל מסוים בתמונה‬
‫‪‬‬
‫‪‬‬
‫‪53‬‬
‫יש לתת קאורדינטת ‪ x,y‬וצבע‪ ,‬ובגישה ישירה לעדכן את‬
‫הפיקסל‪.‬‬
‫יש לשים לב האם הצבע עבור הקאורדינטה המבוקשת נמצא‬
‫בצד הימני אא בצד השמאלי של ה‪ byte -‬בו הוא נשמר‬
‫‪© Keren Kalif‬‬
‫ביחידה זו למדנו‪:‬‬
‫‪ ‬מוטיבציה‬
‫‪ ‬אופרטורים לעבודה עם סיביות‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪54‬‬
‫&‬
‫|‬
‫^‬
‫~‬
‫>>‬
‫<<‬