فصل ۶: فایل‌ها و خطاها — pathlib، UTF-8، CSV، JSON و logging

pathlib: کار با مسیرها بدون دردسر بک‌اسلش ویندوز

مسیر، یک شیء است نه یک رشته

در کدهای قدیمی مسیرها را با رشته و os.path.join می‌ساختند. روش مدرن ماژول pathlib است که مسیر را یک شیء با متدهای مفید می‌کند و تفاوت ویندوز (\) و لینوکس (/) را خودش مدیریت می‌کند.

from pathlib import Path

base = Path(__file__).resolve().parent     # پوشه‌ی همین اسکریپت
data = base / "data"                        # عملگر / مسیر را می‌چسباند
report = data / "orders-1403.csv"

print(report.name)      # orders-1403.csv
print(report.stem)      # orders-1403
print(report.suffix)    # .csv
print(report.parent)    # ...\data
print(report.with_suffix(".json").name)   # orders-1403.json
print(report.exists(), report.is_file())

دام بک‌اسلش در ویندوز

در رشته‌های پایتون، بک‌اسلش شروع «کاراکتر ویژه» است: \n یعنی خط جدید و \t یعنی Tab. پس مسیر "C:\new\test.txt" در واقع شامل یک خط جدید و یک Tab است! سه راه‌حل:

روشنمونهتوصیه
رشته‌ی خام (raw)r"C:\new\test.txt"برای کپی مسیر از Explorer
اسلش رو به جلو"C:/new/test.txt"ویندوز هم می‌پذیرد
pathlibPath("C:/") / "new" / "test.txt"بهترین؛ قابل‌حمل

ساخت، پیدا کردن و پیمایش

out = Path("output") / "reports" / "1403"
out.mkdir(parents=True, exist_ok=True)    # ساخت همه‌ی پوشه‌های میانی، بدون خطا اگر وجود داشت

for csv_file in sorted(Path("data").glob("*.csv")):
    print(csv_file.name, csv_file.stat().st_size, "بایت")

all_json = list(Path("data").rglob("*.json"))   # جست‌وجوی بازگشتی در زیرپوشه‌ها

home = Path.home()                 # C:\Users\نام‌کاربری
desktop = home / "Desktop"

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

برای فایل‌های کوچک، pathlib متدهای یک‌خطی دارد: path.read_text(encoding="utf-8") و path.write_text(text, encoding="utf-8"). برای فایل‌های بزرگ یا خط‌به‌خط، از open در درس بعد استفاده کنید.

مسیر نسبی نسبت به چه؟

مسیر نسبی مثل Path("data") نسبت به پوشه‌ی جاری (current working directory) حل می‌شود، نه نسبت به محل فایل اسکریپت. اگر اسکریپت را از پوشه‌ی دیگری اجرا کنید یا از Task Scheduler، «فایل پیدا نشد» می‌گیرید. برای فایل‌هایی که کنار اسکریپت هستند، همیشه از Path(__file__).resolve().parent شروع کنید.

نکته‌هایی که کمتر کسی می‌داند

  • رشته‌ی خام نمی‌تواند به یک بک‌اسلش تک ختم شود: r"C:\data\" خطای نحوی است. یکی از دلایل خوب برای استفاده از pathlib.
  • Path.cwd() پوشه‌ی جاری را نشان می‌دهد؛ اولین چیزی که هنگام «فایل پیدا نمی‌شود» باید چاپ کنید.
  • path.unlink(missing_ok=True) فایل را حذف می‌کند و اگر نبود خطا نمی‌دهد؛ برای پوشه‌ی پر از shutil.rmtree استفاده کنید (با احتیاط!).
  • glob در ویندوز به بزرگی و کوچکی حروف حساس نیست ولی در لینوکس حساس است؛ *.CSV روی سرور لینوکسی فایل a.csv را پیدا نمی‌کند.
  • os.startfile(path) (فقط ویندوز) فایل را با برنامه‌ی پیش‌فرضش باز می‌کند؛ برای باز کردن خودکار گزارش اکسل بعد از ساخت عالی است.

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