Smart-World Surf

יחידה 8: קלט/פלט קבצים וטיפול בשגיאות

אינטראקציה עם מערכת הקבצים וניהול חריגות.

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

אינטראקציה עם מערכת הקבצים

תוכניות רבות זקוקות ליכולת לאחסן נתונים באופן קבוע, מעבר לזמן הריצה שלהן. מערכת הקבצים מספקת את המנגנון הזה. ב-Python, אנו משתמשים בפונקציות מובנות כדי לפתוח, לקרוא, לכתוב ולסגור קבצים.

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

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

הפעולה הראשונה היא פתיחת הקובץ באמצעות הפונקציה open(), המקבלת את שם הקובץ ומצב הפתיחה. לאחר סיום העבודה עם הקובץ, חובה לסגור אותו באמצעות הפונקציה close() כדי לשחרר משאבים ולשמור שינויים.

'r' (קריאה)

מצב ברירת המחדל. פותח קובץ לקריאה בלבד. אם הקובץ אינו קיים, תתעורר שגיאת FileNotFoundError.

'w' (כתיבה)

פותח קובץ לכתיבה. אם הקובץ קיים, תוכנו יימחק. אם אינו קיים, ייווצר קובץ חדש.

'a' (הוספה)

פותח קובץ לכתיבה, כאשר כל נתון חדש יתווסף לסופו. אם הקובץ אינו קיים, ייווצר קובץ חדש.

'r+' (קריאה וכתיבה)

פותח קובץ לקריאה וכתיבה. הקובץ חייב להתקיים. המצביע מתחיל בתחילת הקובץ.

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

לאחר פתיחת הקובץ, ניתן לבצע פעולות קריאה וכתיבה:

  • file.read(): קורא את כל תוכן הקובץ כמחרוזת אחת.
  • file.readline(): קורא שורה אחת מהקובץ.
  • file.readlines(): קורא את כל השורות בקובץ ומחזיר רשימה של מחרוזות, כאשר כל איבר ברשימה הוא שורה.
  • file.write(string): כותב מחרוזת לקובץ.
  • file.writelines(list_of_strings): כותב רשימת מחרוזות לקובץ.

טיפול בשגיאות וחריגות

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

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

מבנה try-except-else-finally

Python מספקת מבנה מקיף לטיפול בחריגות:

try

הקוד שעלול לעורר חריגה ממוקם בתוך בלוק זה. אם מתרחשת חריגה, הביצוע עובר לבלוק except המתאים.

except

בלוק זה מטפל בחריגה ספציפית או כללית. ניתן להגדיר מספר בלוקי except לטיפול בסוגי חריגות שונים.

else

הקוד בבלוק זה יבוצע רק אם בלוק try הושלם בהצלחה, כלומר, לא התרחשו חריגות.

finally

הקוד בבלוק זה יבוצע תמיד, בין אם התרחשה חריגה ובין אם לאו. הוא משמש לרוב לשחרור משאבים (כמו סגירת קבצים).

ניהול משאבים עם with והחשיבות במבחן

הצהרת with (Context Manager): הצהרת with היא נושא קריטי במבחנים של BGU. היא מבטיחה שמשאבים (כמו קבצים) ייסגרו אוטומטית ובצורה בטוחה, גם אם מתרחשת שגיאה. אי שימוש בהצהרת with בעת עבודה עם קבצים עלול להוביל לבאגים קשים לאיתור, דליפת משאבים, ובמבחן – להורדת נקודות משמעותית. הקפידו להשתמש בה תמיד בעת פתיחת קבצים!

השימוש ב-with open(...) as file: הוא הדרך המועדפת והבטוחה ביותר לעבוד עם קבצים ב-Python. הוא מבטיח שהקובץ ייסגר אוטומטית בסיום הבלוק, גם אם מתרחשת חריגה.

סוגי חריגות נפוצות בקבצים

  • FileNotFoundError: מתרחשת כאשר מנסים לפתוח קובץ שאינו קיים במצב קריאה ('r').
  • PermissionError: מתרחשת כאשר אין לתוכנית הרשאות מתאימות לגשת לקובץ (למשל, לכתוב לקובץ מוגן).
  • IOError / OSError: שגיאות כלליות יותר הקשורות לפעולות קלט/פלט, כמו בעיות חומרה או תקלות במערכת ההפעלה.

מומלץ לטפל בחריגות ספציפיות לפני חריגות כלליות יותר (כגון Exception) כדי לאפשר טיפול ממוקד יותר בבעיה.

שאלות לדיון

  • הסבירו מדוע השימוש בהצהרת with open(...) עדיף על פני פתיחה וסגירה ידנית של קבצים, במיוחד בהקשר של טיפול בשגיאות.
  • מה ההבדל המהותי בין בלוק else לבלוק finally בתוך מבנה try-except, ומתי נשתמש בכל אחד מהם?
  • כתבו קטע קוד ב-Python שמנסה לקרוא קובץ בשם "data.txt". אם הקובץ אינו קיים, עליו ליצור אותו ולכתוב בו את השורה "Hello, BGU!". אם קיימת שגיאת הרשאה, עליו להדפיס הודעה מתאימה. בכל מקרה, עליו להדפיס "Operation complete." בסיום.
  • תארו מצב שבו טיפול לא נכון בחריגות עלול להוביל לבעיות אבטחה או לאובדן נתונים ביישום אמיתי.

נקודות לתשובת מודל

  • with vs. ידני: הצהרת with מבטיחה שהקובץ ייסגר אוטומטית (גם אם מתרחשת חריגה בתוך הבלוק), מונעת דליפת משאבים ופשטנית יותר לקריאה. סגירה ידנית דורשת בלוק finally כדי להבטיח סגירה במקרה של שגיאה, מה שמסרבל את הקוד.
  • else vs. finally: בלוק else יבוצע רק אם בלוק try הושלם ללא חריגות. בלוק finally יבוצע תמיד, בין אם הייתה חריגה ובין אם לאו. else משמש לקוד שצריך לרוץ רק בהצלחה, finally לשחרור משאבים או ניקוי.
  • קוד לדוגמה:
    
    try:
        with open("data.txt", "r") as f:
            content = f.read()
            print(f"קראתי מהקובץ: {content}")
    except FileNotFoundError:
        print("הקובץ 'data.txt' לא נמצא. יוצר קובץ חדש.")
        try:
            with open("data.txt", "w") as f:
                f.write("Hello, BGU!\n")
            print("הקובץ נוצר ונכתב בהצלחה.")
        except PermissionError:
            print("אין הרשאה ליצור או לכתוב לקובץ 'data.txt'.")
    except PermissionError:
        print("אין הרשאה לקרוא את הקובץ 'data.txt'.")
    except Exception as e:
        print(f"אירעה שגיאה בלתי צפויה: {e}")
    finally:
        print("Operation complete.")
    
  • בעיות אבטחה/אובדן נתונים: אי טיפול בשגיאות כתיבה לקובץ עלול לגרום לאובדן נתונים קריטיים. חשיפת הודעות שגיאה מפורטות למשתמש (stack traces) עלולה לחשוף מידע רגיש על מבנה המערכת או נתיבי קבצים, מה שמהווה פרצת אבטחה.
מצאתם טעות או שחסר משהו?
→ הקודמת
ניתוח יעילות ואלגוריתמים
הבאה ←
תכנות מונחה עצמים (OOP)