آموزش پایتون, پایتون سطح متوسط

خواندن و نوشتن فایل‌های متنی در پایتون

خواندن و نوشتن فایل‌های متنی در پایتون

🗓 آخرین به‌روزرسانی:

کار با فایل‌های متنی به برنامه‌های پایتون امکان می‌دهد اطلاعات را بعد از پایان اجرای برنامه نگه دارند، دوباره بخوانند و به‌مرور به‌روزرسانی کنند. با یادگیری تابع open()، حالت‌های مختلف فایل، کدگذاری UTF-8 و ساختار with می‌توان ابزارهایی مانند دفترچه یادداشت، ثبت گزارش، ذخیره تنظیمات و پردازش متن ساخت.

این مطلب، درس یازدهم از دوره رایگان پایتون سطح متوسط است. در درس قبلی مدیریت خطا با try، except، else و finally را یاد گرفتیم. اکنون این مهارت را برای خواندن و نوشتن امن فایل‌های متنی به کار می‌بریم.

فایل متنی چیست؟

فایل متنی داده‌ها را به‌شکل کاراکتر و خط ذخیره می‌کند. فایل‌هایی با پسوندهای .txt، .log، .csv و بسیاری از فایل‌های تنظیمات، متن‌محور هستند. پایتون می‌تواند محتوای این فایل‌ها را بخواند، تغییر دهد یا فایل جدیدی بسازد.

بازکردن فایل با تابع open

ساختار پایه تابع open():

file = open("notes.txt", "r", encoding="utf-8")

پارامترهای مهم:

  • نام یا مسیر فایل
  • حالت بازکردن فایل مانند r، w یا a
  • کدگذاری متن، معمولاً utf-8

چرا باید فایل را ببندیم؟

پس از پایان کار باید فایل بسته شود تا منابع سیستم آزاد و اطلاعات نوشتاری کامل ذخیره شوند:

file = open("notes.txt", "r", encoding="utf-8")
content = file.read()
file.close()

با این حال، روش پیشنهادی استفاده از with است تا فایل حتی هنگام رخ‌دادن خطا نیز به‌صورت خودکار بسته شود.

استفاده از with برای مدیریت فایل

with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()

print(content)

پس از خروج از بلوک with، فایل بسته می‌شود. این ساختار خواناتر و ایمن‌تر از فراخوانی دستی close() است.

حالت‌های بازکردن فایل

حالتکاربردرفتار مهم
rخواندنفایل باید وجود داشته باشد
wنوشتنمحتوای قبلی را حذف می‌کند
aافزودناطلاعات را به انتهای فایل اضافه می‌کند
xساخت فایل جدیداگر فایل موجود باشد خطا می‌دهد
r+خواندن و نوشتنفایل باید وجود داشته باشد
w+خواندن و نوشتنمحتوای قبلی را پاک می‌کند
a+خواندن و افزودننوشتن در انتهای فایل انجام می‌شود
bحالت باینریبرای تصویر، صدا و داده‌های بایتی
tحالت متنیحالت پیش‌فرض فایل‌های متنی

خواندن تمام فایل با read

with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()

print(content)

متد read() کل محتوای فایل را به‌صورت یک رشته برمی‌گرداند. برای فایل‌های کوچک مناسب است، اما برای فایل‌های بسیار بزرگ بهتر است خط‌به‌خط یا بخش‌بخش خوانده شود.

خواندن تعداد مشخصی کاراکتر

with open("notes.txt", "r", encoding="utf-8") as file:
    first_part = file.read(20)

print(first_part)

عدد ارسال‌شده به read() تعداد کاراکترهایی است که خوانده می‌شوند.

خواندن یک خط با readline

with open("notes.txt", "r", encoding="utf-8") as file:
    first_line = file.readline()
    second_line = file.readline()

print(first_line)
print(second_line)

هر بار فراخوانی readline() خط بعدی را می‌خواند. معمولاً نویسه پایان خط نیز در رشته باقی می‌ماند.

خواندن همه خطوط با readlines

with open("notes.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()

print(lines)

خروجی readlines() یک لیست است که هر عنصر آن یک خط فایل است.

پیمایش مستقیم روی فایل

برای پردازش خط‌به‌خط، پیمایش مستقیم معمولاً بهترین انتخاب است:

with open("notes.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line.strip())

این روش همه فایل را یک‌باره وارد حافظه نمی‌کند و برای فایل‌های بزرگ مناسب‌تر است.

حذف فاصله و پایان خط با strip

with open("names.txt", "r", encoding="utf-8") as file:
    names = [line.strip() for line in file if line.strip()]

print(names)

متد strip() فاصله‌ها و نویسه پایان خط را از ابتدا و انتهای رشته حذف می‌کند.

نوشتن در فایل با حالت w

with open("report.txt", "w", encoding="utf-8") as file:
    file.write("گزارش فروش روزانه")

اگر فایل وجود نداشته باشد ساخته می‌شود. اگر وجود داشته باشد، حالت w محتوای قبلی را حذف می‌کند. بنابراین پیش از استفاده از آن باید مطمئن باشید بازنویسی فایل موردنظر است.

نوشتن چند خط

with open("report.txt", "w", encoding="utf-8") as file:
    file.write("گزارش فروش\n")
    file.write("تعداد سفارش: 12\n")
    file.write("درآمد: 4,500,000 تومان\n")

متد write() به‌صورت خودکار خط جدید ایجاد نمی‌کند. برای رفتن به خط بعد باید \n نوشته شود.

متد write چه مقداری برمی‌گرداند؟

with open("message.txt", "w", encoding="utf-8") as file:
    count = file.write("Python")

print(count)

مقدار برگشتی تعداد کاراکترهای نوشته‌شده است.

نوشتن چند رشته با writelines

lines = [
    "خط اول\n",
    "خط دوم\n",
    "خط سوم\n"
]

with open("lines.txt", "w", encoding="utf-8") as file:
    file.writelines(lines)

writelines() نیز به‌طور خودکار \n اضافه نمی‌کند؛ بنابراین باید پایان خط داخل رشته‌ها قرار گیرد.

افزودن اطلاعات با حالت a

with open("activity.log", "a", encoding="utf-8") as file:
    file.write("کاربر وارد سیستم شد\n")

حالت a اطلاعات قبلی را حفظ می‌کند و متن جدید را به انتهای فایل می‌افزاید. این حالت برای گزارش فعالیت، تاریخچه سفارش‌ها و دفترچه یادداشت مناسب است.

جلوگیری از چسبیدن متن جدید به خط قبلی

هنگام افزودن اطلاعات باید مطمئن شوید فایل با خط جدید پایان یافته یا متن جدید با \n شروع می‌شود:

new_note = "تمرین فصل فایل‌ها"

with open("notes.txt", "a", encoding="utf-8") as file:
    file.write(new_note + "\n")

ساخت فایل جدید با حالت x

with open("settings.txt", "x", encoding="utf-8") as file:
    file.write("theme=dark")

اگر فایل از قبل وجود داشته باشد، خطای FileExistsError ایجاد می‌شود. این حالت زمانی مفید است که نمی‌خواهیم فایل موجود به‌اشتباه بازنویسی شود.

کدگذاری UTF-8 چرا مهم است؟

برای ذخیره و خواندن صحیح متن فارسی بهتر است کدگذاری را صریح مشخص کنیم:

with open("persian.txt", "w", encoding="utf-8") as file:
    file.write("آموزش پایتون")

نبود کدگذاری مشخص ممکن است در سیستم‌های مختلف نتیجه متفاوت یا خطای UnicodeDecodeError ایجاد کند.

مسیر نسبی و مسیر مطلق

مسیر نسبی نسبت به پوشه‌ای محاسبه می‌شود که برنامه از آن اجرا شده است:

with open("data/notes.txt", "r", encoding="utf-8") as file:
    print(file.read())

مسیر مطلق محل کامل فایل را مشخص می‌کند:

path = "C:/Users/Mehran/Documents/notes.txt"

مسیر نسبی برای پروژه‌های قابل انتقال مناسب‌تر است، اما باید ساختار پوشه‌ها روشن باشد.

مسیرهای ویندوز و Raw String

در ویندوز بک‌اسلش ممکن است به‌عنوان نویسه ویژه تفسیر شود. می‌توان از Raw String یا اسلش معمولی استفاده کرد:

path1 = r"C:\Users\Mehran\Documents\notes.txt"
path2 = "C:/Users/Mehran/Documents/notes.txt"

پوشه کاری فعلی چیست؟

from pathlib import Path

print(Path.cwd())

متد Path.cwd() پوشه کاری فعلی را نشان می‌دهد و در رفع خطای پیدا نشدن فایل بسیار مفید است.

کار با pathlib

کتابخانه pathlib روش مدرن و خوانایی برای مدیریت مسیرها ارائه می‌دهد:

from pathlib import Path

file_path = Path("data") / "notes.txt"

with file_path.open("r", encoding="utf-8") as file:
    print(file.read())

بررسی وجود فایل

from pathlib import Path

file_path = Path("notes.txt")

if file_path.exists():
    print("فایل وجود دارد")
else:
    print("فایل پیدا نشد")

برای اطمینان از اینکه مسیر واقعاً یک فایل است، می‌توان از is_file() استفاده کرد.

ساخت پوشه پیش از نوشتن فایل

from pathlib import Path

folder = Path("reports")
folder.mkdir(parents=True, exist_ok=True)

file_path = folder / "daily.txt"
file_path.write_text("گزارش امروز", encoding="utf-8")

خواندن و نوشتن سریع با pathlib

from pathlib import Path

file_path = Path("message.txt")
file_path.write_text("سلام پایتون", encoding="utf-8")
content = file_path.read_text(encoding="utf-8")

print(content)

read_text() و write_text() برای فایل‌های کوچک و عملیات ساده بسیار مناسب‌اند.

مدیریت خطای FileNotFoundError

try:
    with open("missing.txt", "r", encoding="utf-8") as file:
        print(file.read())
except FileNotFoundError:
    print("فایل موردنظر پیدا نشد.")

مدیریت چند خطای رایج فایل

try:
    with open("data.txt", "r", encoding="utf-8") as file:
        content = file.read()
except FileNotFoundError:
    print("فایل وجود ندارد")
except PermissionError:
    print("اجازه دسترسی به فایل وجود ندارد")
except UnicodeDecodeError:
    print("کدگذاری فایل با UTF-8 هماهنگ نیست")
except IsADirectoryError:
    print("مسیر واردشده یک پوشه است، نه فایل")
else:
    print(content)

خواندن امن فایل داخل تابع

def read_text_file(path):
    try:
        with open(path, "r", encoding="utf-8") as file:
            return file.read()
    except FileNotFoundError:
        return None

content = read_text_file("notes.txt")

if content is None:
    print("فایل پیدا نشد")
else:
    print(content)

نوشتن امن داخل تابع

def save_text(path, content):
    try:
        with open(path, "w", encoding="utf-8") as file:
            file.write(content)
    except OSError as error:
        return False, str(error)

    return True, None

استفاده از مقدار برگشتی باعث می‌شود تابع بدون چاپ مستقیم پیام، نتیجه عملیات را به بخش دیگر برنامه منتقل کند.

موقعیت نشانگر فایل با tell

with open("notes.txt", "r", encoding="utf-8") as file:
    print(file.tell())
    file.read(10)
    print(file.tell())

tell() موقعیت فعلی نشانگر فایل را برمی‌گرداند.

تغییر موقعیت با seek

with open("notes.txt", "r", encoding="utf-8") as file:
    first = file.read(10)
    file.seek(0)
    all_content = file.read()

seek(0) نشانگر را به ابتدای فایل برمی‌گرداند.

خواندن فایل بزرگ به‌صورت بخش‌بخش

def read_in_chunks(path, chunk_size=1024):
    with open(path, "r", encoding="utf-8") as file:
        while True:
            chunk = file.read(chunk_size)

            if not chunk:
                break

            yield chunk

این روش مانع بارگذاری کل فایل بزرگ در حافظه می‌شود.

شمارش خط‌ها، کلمات و کاراکترها

with open("article.txt", "r", encoding="utf-8") as file:
    text = file.read()

line_count = len(text.splitlines())
word_count = len(text.split())
character_count = len(text)

print("خط:", line_count)
print("کلمه:", word_count)
print("کاراکتر:", character_count)

جست‌وجو در فایل متنی

keyword = "Python"

with open("article.txt", "r", encoding="utf-8") as file:
    for line_number, line in enumerate(file, start=1):
        if keyword.lower() in line.lower():
            print(line_number, line.strip())

جایگزینی متن در فایل

فایل متنی معمولاً مستقیماً در وسط محتوا ویرایش نمی‌شود. ابتدا کل محتوا خوانده، تغییر داده و دوباره نوشته می‌شود:

from pathlib import Path

file_path = Path("article.txt")
content = file_path.read_text(encoding="utf-8")
updated_content = content.replace("پایتون قدیمی", "پایتون جدید")
file_path.write_text(updated_content, encoding="utf-8")

چون write_text() فایل را بازنویسی می‌کند، برای اطلاعات مهم بهتر است ابتدا نسخه پشتیبان تهیه شود.

افزودن تاریخچه به فایل گزارش

from datetime import datetime

message = "ورود کاربر"
time_text = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

with open("app.log", "a", encoding="utf-8") as file:
    file.write(f"[{time_text}] {message}\n")

حذف فایل با pathlib

from pathlib import Path

file_path = Path("temporary.txt")

if file_path.exists():
    file_path.unlink()

حذف فایل قابل بازگشت نیست؛ بنابراین پیش از unlink() مسیر را با دقت بررسی کنید.

تغییر نام و انتقال فایل

from pathlib import Path

old_path = Path("draft.txt")
new_path = Path("archive") / "final.txt"

new_path.parent.mkdir(parents=True, exist_ok=True)
old_path.replace(new_path)

تفاوت فایل متنی و فایل باینری

در حالت متنی، پایتون داده‌ها را به‌صورت رشته و با کدگذاری مشخص پردازش می‌کند. در حالت باینری، داده‌ها به‌صورت bytes خوانده و نوشته می‌شوند:

with open("image.jpg", "rb") as file:
    data = file.read(20)

print(data)

برای فایل‌های تصویری، صوتی، PDF و آرشیوها باید از حالت باینری استفاده شود.

خطاهای رایج هنگام کار با فایل

  • استفاده از w و حذف ناخواسته محتوای قبلی
  • فراموش‌کردن encoding="utf-8" برای متن فارسی
  • استفاده از مسیر نسبی اشتباه
  • فراموش‌کردن \n در write() و writelines()
  • خواندن کل فایل بسیار بزرگ با read()
  • باز نگه‌داشتن فایل به‌دلیل استفاده‌نکردن از with
  • گرفتن همه خطاها با except: و پنهان‌کردن مشکل واقعی
  • تلاش برای نوشتن عدد بدون تبدیل آن به رشته

نوشتن عدد در فایل

score = 18

with open("score.txt", "w", encoding="utf-8") as file:
    file.write(str(score))

پروژه اول: دفترچه یادداشت متنی

در این پروژه کاربر می‌تواند یادداشت جدید ثبت کند، همه یادداشت‌ها را ببیند و فایل را پاک‌سازی کند.

from pathlib import Path

NOTES_FILE = Path("notes.txt")


def add_note():
    note = input("متن یادداشت: ").strip()

    if not note:
        print("یادداشت خالی است.")
        return

    with NOTES_FILE.open("a", encoding="utf-8") as file:
        file.write(note + "\n")

    print("یادداشت ذخیره شد.")


def show_notes():
    if not NOTES_FILE.exists():
        print("هنوز یادداشتی ثبت نشده است.")
        return

    with NOTES_FILE.open("r", encoding="utf-8") as file:
        notes = [line.strip() for line in file if line.strip()]

    if not notes:
        print("فایل یادداشت خالی است.")
        return

    for index, note in enumerate(notes, start=1):
        print(f"{index}. {note}")


def clear_notes():
    NOTES_FILE.write_text("", encoding="utf-8")
    print("یادداشت‌ها پاک شدند.")


while True:
    print("\n1. افزودن یادداشت")
    print("2. نمایش یادداشت‌ها")
    print("3. پاک‌کردن یادداشت‌ها")
    print("4. خروج")

    choice = input("انتخاب: ").strip()

    if choice == "1":
        add_note()
    elif choice == "2":
        show_notes()
    elif choice == "3":
        clear_notes()
    elif choice == "4":
        break
    else:
        print("گزینه نامعتبر است.")

پروژه دوم: تحلیل فایل گزارش

این پروژه تعداد خط‌ها، خطاها و هشدارهای یک فایل گزارش را محاسبه می‌کند:

from pathlib import Path


def analyze_log(path):
    file_path = Path(path)

    if not file_path.is_file():
        return {
            "success": False,
            "message": "فایل پیدا نشد"
        }

    total_lines = 0
    errors = 0
    warnings = 0

    try:
        with file_path.open("r", encoding="utf-8") as file:
            for line in file:
                total_lines += 1
                normalized = line.lower()

                if "error" in normalized:
                    errors += 1

                if "warning" in normalized:
                    warnings += 1
    except (PermissionError, UnicodeDecodeError) as error:
        return {
            "success": False,
            "message": str(error)
        }

    return {
        "success": True,
        "total_lines": total_lines,
        "errors": errors,
        "warnings": warnings
    }


result = analyze_log("app.log")
print(result)

تمرین‌ها

  1. فایلی بسازید و نام، شهر و سن کاربر را در سه خط ذخیره کنید.
  2. برنامه‌ای بنویسید که تمام خط‌های یک فایل را شماره‌گذاری کند.
  3. فقط خط‌های غیرخالی فایل را داخل یک لیست قرار دهید.
  4. تعداد تکرار یک کلمه مشخص را در فایل محاسبه کنید.
  5. برنامه‌ای بنویسید که یک پیام را بدون حذف اطلاعات قبلی به فایل اضافه کند.
  6. محتوای یک فایل را در فایل دیگری کپی کنید.
  7. همه حروف یک فایل را به حالت کوچک تبدیل و در فایل جدید ذخیره کنید.
  8. برنامه‌ای بسازید که وجود فایل را بررسی و در صورت نبودن آن را ایجاد کند.
  9. فایل نمرات را بخوانید و میانگین نمرات معتبر را محاسبه کنید.
  10. دفترچه یادداشت پروژه را با امکان حذف یک یادداشت مشخص توسعه دهید.

📌 همچنین بخوانید: بازار کار پایتون در ایران، دستورهای break، continue و pass در پایتون و ساخت ربات تلگرام با پایتون

پرسش‌های متداول

تفاوت حالت w و a چیست؟

w محتوای قبلی را حذف و از ابتدا می‌نویسد؛ a متن جدید را به انتهای فایل اضافه می‌کند.

بهترین روش بازکردن فایل در پایتون چیست؟

در بیشتر موارد استفاده از with open(...) بهترین روش است، زیرا فایل به‌صورت خودکار بسته می‌شود.

چرا متن فارسی به‌هم‌ریخته نمایش داده می‌شود؟

معمولاً کدگذاری فایل با کدگذاری زمان خواندن هماهنگ نیست. در بیشتر پروژه‌ها از encoding="utf-8" استفاده کنید.

برای فایل‌های بزرگ از چه روشی استفاده کنیم؟

فایل را خط‌به‌خط پیمایش یا در بخش‌های کوچک با read(size) بخوانید؛ از بارگذاری یک‌باره کل فایل خودداری کنید.

آیا write عدد را مستقیماً می‌پذیرد؟

خیر. متد write() در حالت متنی رشته می‌خواهد؛ عدد را با str() یا f-string تبدیل کنید.

تفاوت open و pathlib چیست؟

open() ابزار اصلی کار با فایل است. pathlib مدیریت مسیرها، بررسی وجود فایل و عملیات ساده خواندن و نوشتن را خواناتر می‌کند.

جمع‌بندی

برای کار مطمئن با فایل‌های متنی از with، کدگذاری UTF-8 و حالت مناسب فایل استفاده کنید. r برای خواندن، w برای بازنویسی، a برای افزودن و x برای ساخت فایل جدید است. خطاهای فایل را به‌صورت مشخص مدیریت کنید و برای مسیرها از pathlib کمک بگیرید.

در درس بعدی، با کار با فایل‌های JSON در پایتون آشنا می‌شویم و یاد می‌گیریم داده‌های ساختاریافته را میان دیکشنری‌های پایتون و فایل JSON تبدیل کنیم.

ادامه مسیر یادگیری پایتون

برای یادگیری منظم، آموزش‌های مرتبط زیر را به‌ترتیب دنبال کنید:

می‌خواهی پیشرفتت ذخیره شود؟با ورود یا ثبت‌نام رایگان، درس‌های تمام‌شده را علامت بزن و درصد پیشرفتت را در حساب کاربری ببین.ورود / ثبت‌نام برای ذخیره پیشرفت
درس بعدی · دوره پایتون متوسط (12 از 18)کار با فایل‌های JSON در پایتون؛ خواندن، نوشتن و تبدیل داده‌ها ←
آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.
🧭 مسیر یادگیری پایتون از صفر
ماژول 7: مدیریت خطا و فایل‌ها — درس 32 از 44

برای ذخیره پیشرفت در همه دستگاه‌ها و دریافت گواهی پایان مسیر، رایگان ثبت‌نام کن یا وارد شو.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *