ברוכים הבאים לשיעור זה ביחידה "טיפול בקבצים וניהול שגיאות" בקורס "תכנות וניתוח נתונים בשפת פייתון". ביחידה זו נלמד כיצד לייצר אינטראקציה יעילה ובטוחה עם קבצים במערכת הקבצים, וכיצד לטפל בשגיאות פוטנציאליות באופן חזק ואלגנטי באמצעות מנגנון החריגות של פייתון. הבנה מעמיקה של נושאים אלו חיונית לפיתוח יישומים אמינים ויציבים, המסוגלים להתמודד עם תרחישים שונים של קלט/פלט וטעויות.
אינטראקציה עם קבצים: יסודות
קבצים הם אבן יסוד באחסון נתונים קבוע. בניגוד לנתונים המאוחסנים בזיכרון (RAM) ונעלמים עם סיום התוכנית, נתונים בקבצים נשמרים גם לאחר שהתוכנית מסתיימת. פייתון מספקת ממשק פשוט ועוצמתי לעבודה עם קבצים.
פתיחת קובץ: הפונקציה open()
האינטראקציה הראשונה עם קובץ מתבצעת באמצעות הפונקציה המובנית open(). פונקציה זו מחזירה אובייקט קובץ (file object) שדרכו ניתן לבצע פעולות קריאה וכתיבה.
התחביר הבסיסי הוא: open(file_path, mode).
מצבי קובץ (File Modes)
הארגומנט mode קובע את אופן האינטראקציה עם הקובץ. בחירת המצב הנכון קריטית למניעת שגיאות ולשמירה על שלמות הנתונים.
'r' (קריאה)
מצב ברירת מחדל. פותח קובץ לקריאה בלבד. אם הקובץ לא קיים, תועלה שגיאה (FileNotFoundError).
'w' (כתיבה)
פותח קובץ לכתיבה. אם הקובץ קיים, תוכנו יימחק. אם הקובץ לא קיים, הוא ייווצר. זהירות: מחיקת תוכן קיים!
'a' (הוספה)
פותח קובץ לכתיבה, כאשר כל כתיבה חדשה מתווספת לסוף הקובץ. אם הקובץ לא קיים, הוא ייווצר.
'r+' (קריאה וכתיבה)
פותח קובץ לקריאה וכתיבה. הקובץ חייב להתקיים. מצביע הקובץ ממוקם בתחילה.
קריאה וכתיבה לקבצים
file.read(): קורא את כל תוכן הקובץ כמחרוזת אחת.file.readline(): קורא שורה אחת מהקובץ.file.readlines(): קורא את כל השורות בקובץ ומחזיר רשימה של מחרוזות, כאשר כל מחרוזת היא שורה.file.write(string): כותב מחרוזת לקובץ.file.writelines(list_of_strings): כותב רשימה של מחרוזות לקובץ.
with statement:
חובה להשתמש ב-with open(...) as f:. מבנה זה מבטיח שהקובץ ייסגר אוטומטית (גם אם מתרחשת שגיאה), ומונע דליפות משאבים. אי שימוש ב-with הוא טעות נפוצה שעלולה להוביל לבעיות ביצועים או לשחיתות נתונים.
טיפול בשגיאות באמצעות חריגות (Exceptions)
תוכניות פייתון אינן פועלות תמיד בתנאים אידיאליים. קבצים עשויים לא להימצא, משתמשים עשויים להזין קלט שגוי, או חיבורי רשת עלולים להיכשל. במקום לקרוס, תוכנה חזקה צריכה לדעת לטפל בתרחישים אלו באלגנטיות. כאן נכנסות לתמונה החריגות.
בלוקי try-except
בלוק try-except הוא המנגנון העיקרי לטיפול בחריגות בפייתון.
try-except: מבנה קוד המאפשר לנסות לבצע קטע קוד שעלול להעלות חריגה (בבלוק try), ולספק קוד חלופי שירוץ במקרה של חריגה (בבלוק except).
try:
# קוד שעלול להעלות חריגה
file = open("non_existent_file.txt", "r")
content = file.read()
file.close()
except FileNotFoundError:
# קוד לטיפול בחריגה ספציפית
print("שגיאה: הקובץ לא נמצא.")
except Exception as e:
# קוד לטיפול בכל חריגה אחרת
print(f"אירעה שגיאה כללית: {e}")
else:
# קוד שירוץ רק אם לא הועלתה חריגה בבלוק try
print("הקובץ נקרא בהצלחה.")
finally:
# קוד שירוץ תמיד, בין אם הייתה חריגה ובין אם לא
print("ניסיון לטפל בקובץ הסתיים.")
טיפול בחריגות ספציפיות לעומת חריגות כלליות
מומלץ תמיד לטפל בחריגות ספציפיות ככל האפשר. טיפול בחריגה כללית (except Exception) עלול להסתיר בעיות אמיתיות ולמנוע דיבוג יעיל.
FileNotFoundError: קובץ לא נמצא.IOError: שגיאת קלט/פלט כללית (למשל, אין הרשאות כתיבה).ValueError: ערך לא חוקי (למשל, ניסיון להמיר מחרוזת שאינה מספר למספר).TypeError: פעולה על טיפוס נתונים לא נכון.
שאלות לדיון
- הסבירו מדוע השימוש ב-
with open(...) as f:עדיף על פני פתיחת קובץ ידנית וסגירתו באמצעותf.close(). - תארו תרחיש שבו שימוש במצב קובץ 'w' (כתיבה) ללא זהירות עלול להוביל לאובדן נתונים חמור. כיצד ניתן למנוע זאת?
- כתבו קטע קוד קצר המנסה לקרוא מספר שלם מקובץ בשם "numbers.txt". אם הקובץ לא קיים, צרו אותו וכתבו בו את המספר 0. אם הקובץ קיים אך מכיל טקסט שאינו מספר, הדפיסו הודעת שגיאה מתאימה.
- מה ההבדל בין בלוק
exceptלבלוקfinallyבטיפול בחריגות, ומתי נשתמש בכל אחד מהם?
נקודות לתשובת מודל
withstatement: מבטיח סגירה אוטומטית של הקובץ, גם במקרה של חריגה, ובכך מונע דליפות משאבים ופגיעה בביצועים או בשלמות הנתונים.- סכנת 'w': מצב 'w' מוחק את כל תוכן הקובץ הקיים. ניתן למנוע אובדן נתונים על ידי בדיקה האם הקובץ קיים לפני הפתיחה (למשל, באמצעות
os.path.exists()), או על ידי שימוש במצב 'a' (הוספה) אם המטרה היא להוסיף תוכן ולא להחליף. - קוד לדוגמה (קריאת מספר):
import os try: with open("numbers.txt", "r") as f: num_str = f.read().strip() number = int(num_str) print(f"המספר שנקרא מהקובץ: {number}") except FileNotFoundError: print("הקובץ לא נמצא, יוצר אותו עם המספר 0.") with open("numbers.txt", "w") as f: f.write("0") except ValueError: print("שגיאה: הקובץ מכיל תוכן שאינו מספר שלם.") except Exception as e: print(f"אירעה שגיאה בלתי צפויה: {e}") exceptvs.finally: בלוקexceptמטפל בחריגה ספציפית או כללית שהועלתה בבלוקtry, ומאפשר לתוכנית להמשיך לפעול או לטפל בשגיאה. בלוקfinallyמבטיח שקוד מסוים ירוץ תמיד, ללא קשר אם חריגה התרחשה או טופלה, ומשמש בדרך כלל לשחרור משאבים (כמו סגירת קבצים אם לא נעשה שימוש ב-with) או ניקוי.