Smart-World Surf

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

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

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

טיפול בקבצים בפייתון

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

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

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

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

מצב 'r' (read)

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

מצב 'w' (write)

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

מצב 'a' (append)

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

מצב 'x' (exclusive creation)

פתיחה לכתיבה, אך רק אם הקובץ אינו קיים. אם הקובץ קיים, תתעורר שגיאת FileExistsError.

לצד מצבים אלו, ניתן להוסיף 'b' לעבודה עם קבצים בינאריים (לדוגמה, 'rb', 'wb') או '+' כדי לאפשר גם קריאה וגם כתיבה (לדוגמה, 'r+', 'w+').

ניהול משאבים עם with open()

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

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

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

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

מבנה try-except-else-finally

try

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

except

מטפל בחריגות ספציפיות (או בכל חריגה). ניתן לציין סוג חריגה (לדוגמה, except FileNotFoundError:).

else

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

finally

קוד שמתבצע תמיד, ללא קשר אם התרחשה חריגה או לא. אידיאלי לשחרור משאבים (לדוגמה, סגירת קבצים אם לא השתמשנו ב-with).

חריגות נפוצות

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

שילוב טיפול בקבצים וטיפול בשגיאות

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

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

דוגמה: ניסיון לקרוא מקובץ שייתכן שאינו קיים, ולטפל בשגיאה אם הוא אכן חסר:

try:
    with open("my_data.txt", "r") as f:
        content = f.read()
        print("תוכן הקובץ:", content)
except FileNotFoundError:
    print("שגיאה: הקובץ 'my_data.txt' לא נמצא.")
except IOError as e:
    print(f"שגיאת קלט/פלט בעת גישה לקובץ: {e}")
except Exception as e:
    print(f"אירעה שגיאה בלתי צפויה: {e}")
else:
    print("הקובץ נקרא בהצלחה.")
finally:
    print("סיום ניסיון קריאת קובץ.")

שאלות לדיון

  • מדוע השימוש ב-with open(...) עדיף על פני פתיחה וסגירה ידנית של קבצים באמצעות open() ו-file.close()?
  • הסבירו את סדר הביצוע של הבלוקים try, except, else ו-finally, ותנו דוגמה לכל אחד.
  • כיצד הייתם מטפלים במצב שבו תוכנה מנסה לכתוב לקובץ, אך אין לה הרשאות כתיבה לתיקייה?
  • מתי עדיף להשתמש בבלוק except כללי (לדוגמה, except Exception:) ומתי עדיף לציין סוגי חריגות ספציפיים?

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

  • with open(...): מבטיח סגירה אוטומטית של הקובץ גם במקרה של שגיאה בתוך הבלוק, מונע דליפת משאבים ומפשט את הקוד.
  • סדר ביצוע try-except-else-finally:
    • try: מבוצע ראשון.
    • אם אין חריגה: else מבוצע, ואז finally.
    • אם יש חריגה: except מתאים מבוצע, ואז finally.
    • finally: מבוצע תמיד, ללא קשר לתוצאה.
  • טיפול בהרשאות כתיבה: יש להשתמש בבלוק try-except ולצפות לחריגות כמו PermissionError (או IOError כללי יותר). בתוך ה-except, ניתן להציג הודעת שגיאה למשתמש או לנסות נתיב חלופי.
  • except כללי מול ספציפי:
    • ספציפי: עדיף ברוב המקרים. מאפשר לטפל בכל סוג שגיאה באופן ממוקד ושונה, משפר את קריאות הקוד ומקל על ניפוי באגים.
    • כללי: יש להשתמש בזהירות רבה, בעיקר במקרים שבהם לא ניתן לצפות את כל סוגי השגיאות, או כ"מלכודת" אחרונה לאחר טיפול בחריגות ספציפיות. עלול להסתיר באגים אמיתיים.
מצאתם טעות או שחסר משהו?
→ הקודמת
בקרת זרימה ופונקציות
הבאה ←
תכנות מונחה עצמים (OOP)