Menu

טיפול בקבצים ב-Python: קריאה, כתיבה והוספה לקבצים בבטחה

איך קוראים וכותבים קבצים ב-Python: הצהרת with, מצב טקסט מול מצב בינארי, וה-API המודרני והבטוח יותר שמבוסס על נתיבים.

קבצים הם פשוט מחרוזות עם נתיב

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

בואו נעבור על המקרים הנפוצים.

קריאת קובץ שלם

הקריאה הפשוטה ביותר:

with open("notes.txt") as f:
    contents = f.read()

print(contents)

open("notes.txt") פותחת את הקובץ לקריאה (ברירת המחדל). בלוק ה-with אומר ש-Python תסגור את הקובץ כשיוצאים מהבלוק, גם אם נזרקת חריגה. אחרי הסגירה אי אפשר להשתמש יותר ב-f; הטקסט נמצא ב-contents.

contents היא מחרוזת אחת שמכילה את כל הקובץ. מתאים לקבצים קטנים; גרוע ללוג של 2 GB.

קריאה שורה אחרי שורה

בקבצים גדולים יותר, עברו על הקובץ בלולאה במקום לקרוא את הכל לזיכרון:

with open("big.log") as f:
    for line in f:
        if "ERROR" in line:
            print(line.strip())

כל איטרציה מחזירה שורה אחת כולל ירידת השורה שבסופה, ולכן .strip() מופיעה כל כך הרבה. אם רוצים רשימה של שורות, f.readlines() עושה את זה, אבל בדרך כלל מעבר ישיר בלולאה הוא מה שצריך.

כתיבה לקובץ

כדי לכתוב, העבירו את המצב כארגומנט שני:

with open("output.txt", "w") as f:
    f.write("first line\n")
    f.write("second line\n")

שני דברים שכדאי לשים לב אליהם:

  • "w" דורס. אם output.txt כבר קיים, התוכן שלו נעלם ברגע ש-open רצה.
  • את ירידות השורה צריך להוסיף בעצמכם. f.write("hello") כותבת בדיוק את חמשת התווים האלה, בלי ירידת שורה בסוף.

כדי להוסיף לסוף הקובץ במקום לדרוס:

with open("output.txt", "a") as f:
    f.write("another line\n")

אפשר גם להזין כמה שורות בבת אחת עם writelines:

lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
    f.writelines(lines)

אותו כלל: את ירידות השורה אתם מספקים.

ל-print יש ארגומנט file, שהוא דרך קלה לכתוב בלי ירידות שורה ידניות:

with open("log.txt", "w") as f:
    print("started", file=f)
    print("finished", file=f)

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

מצב טקסט מול מצב בינארי

כברירת מחדל, open עובדת במצב טקסט. Python מפענחת בתים למחרוזות (עם UTF-8 כברירת מחדל בפלטפורמות מודרניות) ומטפלת בהמרת סימני סוף השורה.

לתמונות, קובצי PDF, קבצים מקומפלים או כל דבר שאינו טקסט, פתחו במצב בינארי על ידי הוספת "b" למצב:

with open("image.png", "rb") as f:
    data = f.read()

print(len(data))  # מספר הבתים

with open("image_copy.png", "wb") as f:
    f.write(data)

במצב בינארי מקבלים אובייקטי bytes במקום str, ו-Python לא נוגעת בסימני סוף השורה.

הגדרת קידוד

בקובצי טקסט, היו מפורשים לגבי הקידוד. UTF-8 כמעט תמיד נכון ב-2026:

with open("notes.txt", encoding="utf-8") as f:
    contents = f.read()

אם אתם מתמודדים עם קבצים ישנים מסביבה שעבדה רק עם Windows, ייתכן שתראו גם cp1252 או latin-1. ניחוש שגוי ייתן תווים משובשים או UnicodeDecodeError.

pathlib: הדרך המודרנית לטפל בנתיבים

המודול pathlib של הספרייה הסטנדרטית נותן API נוח יותר ממחרוזות גולמיות:

from pathlib import Path

path = Path("notes.txt")

# קריאה וכתיבה פשוטות.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")

# בונים נתיבים בלי לדאוג ל-/ מול \.
data_dir = Path("data")
log_path = data_dir / "today.log"

print(log_path)
print(log_path.exists())
print(log_path.suffix)       # ".log"
print(log_path.stem)         # "today"
print(log_path.parent)       # "data"

Path.read_text() ו-write_text() הן קיצורי דרך לדפוס with open(...) as f כשרוצים פשוט לקרוא ולכתוב הכל בבת אחת. למעבר שורה אחרי שורה, עדיין משתמשים ב-open או ב-path.open().

דוגמה קטנה מקצה לקצה

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

from pathlib import Path

source = Path("items.txt")
destination = Path("filtered.txt")

items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]

destination.write_text("\n".join(kept) + "\n")

print(f"Kept {len(kept)} items out of {len(items)}")

splitlines() היא בת הזוג של join לעבודה עם שורות. היא מפצלת לפי תווי ירידת שורה בלי לשמור אותם: שימושי כשממילא מחברים את החלקים מחדש.

כשמשהו משתבש

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

בינתיים, הצצה מהירה לאיך נראה טיפול בשגיאות:

from pathlib import Path

path = Path("maybe.txt")

try:
    contents = path.read_text()
except FileNotFoundError:
    print("File doesn't exist - starting fresh.")
    contents = ""

print(repr(contents))

הרגלים חשובים

  • השתמשו תמיד ב-with open(...) במקום ב-open גולמי עם סגירה ידנית.
  • העבירו תמיד encoding= בקובצי טקסט; UTF-8 כברירת מחדל.
  • עברו על קבצים גדולים שורה אחרי שורה; אל תקראו אותם בשלמותם עם .read().
  • לנתיבים ולדפוסי קריאה וכתיבה נפוצים, השתמשו ב-pathlib: זה יחסוך לכם הרבה אקרובטיקה עם מחרוזות.

שאלות נפוצות

איך קוראים קובץ ב-Python?

השתמשו ב-open() יחד עם הצהרת with, שסוגרת את הקובץ אוטומטית כשמסיימים. with open('file.txt') as f: contents = f.read() קוראת את כל הקובץ לתוך מחרוזת. לקריאה שורה אחרי שורה, עברו בלולאה ישירות על אובייקט הקובץ: for line in f:.

מה ההבדל בין מצבי הפתיחה 'r', 'w' ו-'a'?

'r' הוא קריאה (ברירת המחדל). 'w' הוא כתיבה: הוא יוצר את הקובץ, או מרוקן אותו אם הוא קיים. 'a' הוא הוספה: הוא מוסיף לסוף הקובץ בלי למחוק את מה שכבר יש בו. הוסיפו 'b' למצב בינארי או '+' לקריאה וכתיבה.

למה להשתמש ב-with open במקום ב-open רגיל?

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

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל