המדריך השלם
 

קבצים

בתוכניות מחשב רבות יש צורך לשמור את הנתונים - תוכנות כמו מעבדי תמלילים, יומני פגישות, הנהלת חשבונות וכדומה שומרות נתונים לשימוש חוזר. בכל התוכניות שהצגנו שמרנו את הנתונים בזיכרון של המחשב, אך כאשר כיבינו את המחשב הנתונים הללו נמחקו מהזיכרון. כאשר אנו כותבים מסמך במעבד תמלילים נרצה לשמור את המידע בצורה כלשהוא ובמידת הצורך לטעון את המידע בחזרה לזיכרון גם לאחר זמן רב.
קיימים התקני אחסון חיצוניים לזיכרון המחשב: דיסק קשיח, תקליטון או תקליטור אופטי ועוד. באמצעים אלה ניתן לשמור את הנתונים ללא תלות בכיבוי המחשב או בסיום בלתי צפוי של התוכנית. לשם כך נרכז את הנתונים שנרצה לשמור בקבצים.
קובץ - אוסף של בתים שיש קשר איכות בניהם ויש לו שם שנקבע על ידי המשתמש. מערכת ההפעלה היא האחראית לנהל את השמירה של הנתונים בקבצים ואת הטעינה שלהם (היא עושה זאת על ידי ניהול טבלה בה רשומים שמות הקבצים ומיקומם).

קיימים שני סוגי קבצים: קבצי טקסט וקבצים בינאריים. בפרק זה נעסוק בקבצי טקסט, נראה כיצד פותחים קובץ, כותבים בו או קוראים ממנו וסגירתו.
ברב הקבצים קיים פורמט מסוים שמוכר לתוכניות שכותבות או קוראות ממנו. פורמט זה מציין כיצד המידע מאוחסן בקובץ. בכל תוכנית ניתן לקבוע פורמט עבור סוג הנתונים שצריך לשמור בו - לדוגמא, אם נכתוב תוכנית לניהול ספר טלפוניים נוכל לבנות את הפורמט כך ששדהו הראשון יהיה מספר הרשומות בקובץ, שדהו השני מספר המציין את סוג המיון (מספרי ,אלפבתי), שדהו השלישי תו המציין אם הנתונים הם בעברית או באנגלית ועוד שדות בהתאם לרצוננו.

קובץ טקסט

סוג קובץ זה מיועד להיקרא על ידי כל תוכנית המסוגלת לקרוא קבצי טקסט כמו edit, dos,מעבדי תמלילים ועוד. בקובץ זה לא מופיעים תווים מיוחדים כמו null.
הוא ערוך בשורות אשר מופרדות על ידי התווים 'n\' ו 'r\' ובסיום כל קובץ נמצא גם התו eof המציין סוף קובץ (end of file).
כדי לגשת לקובץ נגדיר משתנהf FILE* שהוא מצביע לקובץ (מצביע *). תו הכוכבית מציין כי f אינו קובץ בעצמו אלא מצביע לראשיתו (בפרקים על מבני נתונים נעסוק בהרחבה במצביעים, כרגע חשוב רק להבין שכדי לקרוא\לכתוב לקובץ נציין את ראשיתו על ידי אופרטור הכוכבית).

מבנהו של file בספרייה stdio:

typedef struct
{
    short evel;
    unsigned flags;
    char fd;
    unsigned char hold;
    short bsize;
    unsigned char *buffer, *curp;
    unsigned istemp;
    short token;
}FILE;
נסביר את חלקם:
fd - מספר הזיהוי של הקובץ במערכת ההפעלה.
buffer - החוצץ שדרכו מתבצעת הקריאה והכתיבה מהקובץ.
curp - מצביע על המיקום הנוכחי בקובץ.

סוגי גישה לקובץ

r - קריאה בלבד מקובץ קיים.
w - כתיבה בלבד, אם הקובץ קיים הוא ימחק.
a - הוספה לקובץ קיים. אם לא קיים נוצר חדש כך שהפעולה של פקודת append שקולה ליצירת קובץ חדש.
+r - קריאה וכתיבה לקובץ קיים.
+w - ריאה וכתיבה לקובץ אם הקובץ קיים הוא ימחק.
+a - הוספה לקובץ ואפשרות קריאה ממנו.

פתיחה וסגירה של קבצים

הפונקציה fopen():
כדי לקרוא או לכתוב לקובץ יש צורך בפתיחתו. פתיחת הקובץ נעשית על ידי קריאה לפונקציה fopen (פונקציה זו מצויה בספריה stdio ) המקבלת כפרמטר שם קובץ וסוג גישה (קריאה\ כתיבה).
לאחר תו זה נוסיף תו שיציין אם הקובץ הוא קובץ טקסט או בינארי, אם הקובץ הוא קובץ טקסט נוסיף את התו t, אם הקובץ הוא קובץ בינארי נוסיף את התו b.
לדוגמא: קיים קובץ טקסט הנקרא ""file , נפתח אותו לקריאה כדלהלן:

FILE *f = fopen ("file.txt", rt");
על פי התבנית לפתיחת קובץ.

התבנית לפתיחת קובץ:
FILE *f = fopen (file_name, access_type);
:או
FILE *f;
f = fopen (file_name , access_type);
כאשר f הוא משתנה מסוג מצביע למבנה FILE(נדון בפירוט בחלק של מבנה הנתונים במצביעים).
שם קובץ - שם קובץ חוקי מורכב משם וסיומת המעידה על אופיו כמו: bat, tif, gif, jpeg וכו' המופרדים בנקודה. בקבצי טקסט הסיומת המקובלת היא txt .

חשוב מאוד לבדוק אם פתיחת הקובץ הסתיימה בהצלחה או נכשלה.
הפונקציה fopen מחזירה null כאשר פתיחת הקובץ נכשלה ולכן נבדוק שהערך המוחזר מהפונקציה שונה מ- null. כישלון בפתיחת הקובץ יכול להתרחש מכמה סיבות:
1. שם קובץ לא חוקי
2. לא קיים קובץ עם שם זה
3. ניסיון לפתוח קובץ לכתיבה כאשר הוא קובץ לקריאה בלבד
4. אין הרשאות לפתיחת הקובץ

כאשר פתיחת הקובץ חיונית לתוכנית ופעולה זו נכשלה נרצה לסיים את התוכנית לשם כך נשתמש בפונקציה exit המופיעה בספרייה stdlib כך:

FILE *tf = fopen ("file_name.txt", "wt");
if (tf == null)
{
    printf("failed to open the text file");
    exit (1);
}

הפונקציה fclose(): לאחר השימוש בקובץ יש לסגור אותו. הפונקציה שמבצעת זאת היא fclose הנמצאת בספרייה stdio המקבלת כארגומנט מצביע לקובץ. הפונקציה 0 אם הסגירה הצליחה אחרת 1- המציין EOF (end of file).

התבנית לסגירת קובץ:
fclose (poiner_2_file);

הפונקציה feof (pointer_to_file):
על מנת לבדוק אם הגענו לסוף הקובץ יש להשתמש בפונקציה feof הנמצאת גם היא בספרייה stdio ומקבלת כארגומט מצביע לקובץ, מחזירה 0 אם לא הגענו לסוף הקובץ אחרת ערך שונה מ- 0.

כתיבה וקריאה מקבצים

fprintf (pointer_to_file, " …", list_of_variables)
פונקצית כתיבה לקובץ, דומה לפונקצית כתיבה למסך (התקן הפלט הסטנדרטי) רק בתוספת f בתחילה המציינת כי יש לכתוב לקובץ (file).
היא מקבלת כארגומנט מצביע לקובץ, ואח"כ הכל זהה לפונקציה printf.

fscanf (pointer_to_file, "..", list_of_variables)
כמו כן הפונקציה לקריאה מהקובץ דומה לפונקצית קריאה מהמקלדת (התקן הקלט הסטנדרטי) בתוספת f מהסיבה שהוזכרה. כמו ב- fprintf יש לשלוח כארגומנט את המצביע לקובץ.

ניתן להשתמש בפונקציה fprintf גם כאשר רוצים לקלוט נתונים מהתקן הקלט הסטנדרטי (מקלדת) על ידי כך שבשדה הראשון של הפונקציה fprintf נכתוב .stdin כנ"ל לגבי fscanf כאשר בשדה הראשון נכתוב stdout.
דוגמא 1:

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

FILE *f;
char file_name[15];
char c;

void write_2_file (char file_name[])
{
    f = fopen(file_name, "wt");
    if (f == NULL)
       exit(1);
    else
    {
       printf("The file %s has been opened \n\r", file_name);
       printf ("Enter text to the file \n\r");
       fflush (stdin); //cleaning the buffer
       for (fscanf(stdin, "%c", &c); !feof (stdin); fscanf (stdin, "%c", &c))
          fprintf (f, "%c", c);
       if (fclose(f))
          exit (1); //the closing wasnt sucssesful
       else
          printf ("\n\rThe file %s has been closed\n\r", file_name);
    }
}

void read_from_file (char file_name[])
{
    FILE *f;
    printf("Reading from the file %s :\n\r",file_name);
    f = fopen (file_name, "rt");
    if (f == NULL)
    {
       printf ("Can't open the file %s ", file_name);
       exit(1);
    }
    else
    {
       printf("The file %s has been opened \n\r", file_name);
       for (fscanf(f,"%c", &c); !feof (f); fscanf (f,"%c", &c))
          fprintf (stdout, "%c", c);
       if (fclose(f))
          exit (1); //the closing wasnt sucssesful
       else
          printf ("\n\rThe file %s has been closed", file_name);
    }

}

void main()
{
    printf ("\n\rEnter file name to create: ");
    scanf ("%s", file_name);

    write_2_file (file_name);
    read_from_file (file_name);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


דוגמא 2:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

FILE *from_f;
FILE *to_f;
char from_file[15];
char to_file[15];

char c;

void coping (char from_file[], char to_file[])
{
    from_f = fopen (from_file, "rt");
    to_f = fopen (to_file, "wt");

    if ((from_f == NULL) || (to_f == NULL))
       exit(1);
    else
    {
       printf("The files %s and %s has been opened \n\r", from_file, to_file);
       printf("The text in the file %s\n\r", from_file);
       for (fscanf(from_f, "%c", &c); !feof (from_f); fscanf (from_f, "%c", &c))
       {
          fprintf (to_f, "%c", c);
          fprintf (stdout,"%c", c);
       }
       if ((fclose(to_f)) || (fclose (from_f)))
          exit (1); //the closing wasnt sucssesful
       else
          printf ("\n\rThe files %s and %s has been closed\n\r", from_file, to_file);
    }
}

void main()
{
    printf ("\n\rEnter file name to copy: ");
    scanf ("%s", from_file);
    printf ("\n\rEnter a new file name: ");
    scanf ("%s", to_file);
    coping (from_file, to_file);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


דוגמא 3:

התוכנית קולטת שמות של שני קבצים ובודקת האם הם זהים בתוכנם.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

FILE *f1;
FILE *f2;
char first_f[15];
char second_f[15];

char c1,c2;
int flag = 1;

void compare (char first_f[], char second_f[])
{
    f1 = fopen (first_f, "rt");
    f2 = fopen (second_f, "rt");

    if ((f1 == NULL) || (f2 == NULL))
       exit(1);
    else
    {
       printf("The files %s and %s has been opened \n\r", first_f, second_f);

       for ( (fscanf(f1, "%c", &c1)) && (fscanf (f2, "%c", &c2));
          (!feof (f1)) && (!feof (f2));
          (fscanf (f1, "%c", &c1))&& (fscanf (f2, "%c", &c2)) )
          {
             if (! c1 == c2)
             {
                printf ("\n\rThe two files are not the same ");
                flag = 0;
                break;
             }
             fprintf (stdout,"%c", c1);
          }
          if (flag)
             printf("\n\rThe two files are the same");
          if ((fclose(f1)) || (fclose (f2)))
             exit (1); //the closing wasnt sucssesful
          else
             printf ("\n\rThe files %s and %s has been closed\n\r", first_f, second_f);
    }
}

void main()
{
    printf ("\n\rEnter the first file name: ");
    scanf ("%s", first_f);
    printf ("\n\rEnter the second file name: ");
    scanf ("%s", second_f);
    compare (first_f, second_f);
}


פונקציות נוספות לשימוש בקבצים

fgetc(pointer_to_file) - קריאת תו מקובץ.

fputc(char, pointer_to_file) - כתיבת תו לקובץ.

fgets(string, max_leng, pointer_to_file) - קריאת מחרוזת לתוך משתנה מחרוזת (string) מקובץ.

fputs(string, pointer_to_file) - כתיבת שורה שלמה לתוך קובץ.

השימוש בהם נעשה בדומה לשימושים של הפונקציות שהצגנו בפרק הקלט/פלט (putc, puts, gets, getc וכו').

דוגמא 4:

תוכנית הבודקת את מס' המופעים של תו נתון בקובץ נתון.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

FILE *f;

void count (char ch, char file_n[])
{
    int num = 0;
    char c;
    if ((f = fopen (file_n, "rt")) == NULL)
    {
       printf("\n\rCan't open file %s ", file_n);
       exit(1);
    }
    else
    {
       printf("The file %s has been opened \n\r", file_n);

       for (c = fgetc(f); !feof (f); c = fgetc (f))
       {
          if (c == ch)
             num++;
          else
             continue;
       }
       printf("\n\rThe are %d %c in the file %s",num ,ch, file_n);
       if (fclose(f))
          exit (1); //the closing wasnt sucssesful
       else
       printf ("\n\rThe files %s has been closed\n\r", file_n);
    }
}

void main()
{
    char ch;
    char file_name[15];

    printf ("\n\rEnter the char : ");
    scanf ("%c", &ch);
    printf ("\n\rEnter the name of a file: ");
    scanf ("%s", file_name);
    count (ch, file_name);
}



מבחן
© איתן 2003. כל הזכויות שמורות למערכת המידע איתן.