FA-TOOLS — Header Component

آموزش جامع کتابخانه shutil در پایتون: راهنمای عملی کپی، جابجایی و حذف فایل‌ها

خلاصه سریع: کتابخانه shutil در پایتون قدرتمندترین ابزار استاندارد برای مدیریت فایل‌ها در سطح کلان است. با این ماژول می‌توانید فایل‌ها را با حفظ متادیتا کپی کنید، پوشه‌ها را به صورت درختی جابجا یا حذف کنید، و حتی کل پوشه‌ها را به فایل‌های Zip یا Tar تبدیل کنید؛ کارهایی که با ماژول ساده‌ی os به راحتی امکان‌پذیر نیستند.

مدیریت فایل‌ها و پوشه‌ها یکی از پایه‌ای‌ترین نیازها در برنامه‌نویسی است. اگرچه ماژول استاندارد os ابزارهای خوبی برای کار با مسیرها و فایل‌های تک تکی ارائه می‌دهد، اما زمانی که نیاز به کپی کردن، انتقال کل پوشه‌ها به همراه محتویاتشان یا فشرده‌سازی سیستم‌های فایل دارید، ماژول shutil (مخفف Shell Utilities) وارد میدان می‌شود. این کتابخانه به طور پیش‌فرض در پایتون نصب است و بدون نیاز به نصب هیچ ابزار جانبی، امکانات پیشرفته‌ای برای تعامل با سیستم‌عامل در اختیارتان می‌گذارد.

کپی کردن فایل‌ها و پوشه‌ها با shutil

آموزش shutil در پایتون: کپی، جابجایی و حذف فایل — تصویر 1

کدام متد کپی در پایتون بهتر است؟ پاسخ بستگی به نیاز شما به حفظ «متادیتا» (مانند زمان ایجاد، آخرین ویرایش و مجوزهای دسترسی) دارد. متد shutil.copy2() بهترین و امن‌ترین گزینه برای اکثر سناریوهاست چون متادیتا را نیز کپی می‌کند، در حالی که shutil.copy() فقط محتوا و مجوزها را کپی می‌کند.

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

۱. کپی کردن یک فایل ساده

متد shutil.copyfile() محتوای یک فایل را بدون در نظر گرفتن متادیتا در مقصد بازنویسی می‌کند. توجه داشته باشید که در این متد، مقصد حتماً باید نام یک فایل باشد، نه یک پوشه.

import shutil

# کپی ساده فایل به مقصد مشخص
shutil.copyfile('source.txt', 'destination.txt')

۲. کپی فایل به درون یک پوشه با copy و copy2

اگر مقصد شما یک پوشه است، از دو متد copy() یا copy2() استفاده کنید. تفاوت بزرگ این دو در حفظ زمان آخرین تغییرات (Modification Time) و دسترسی‌های فایل است.

# کپی معمولی (فقط محتوا و مجوزها)
shutil.copy('source.txt', '/path/to/backup_folder/')

# کپی پیشرفته (حفظ کامل متادیتا مانند زمان ویرایش فایل)
shutil.copy2('source.txt', '/path/to/backup_folder/')

۳. کپی کردن یک پوشه به صورت کامل (کپی درختی)

برای کپی کردن کل یک پوشه به همراه تمام زیرپوشه‌ها و فایل‌های درون آن، از shutil.copytree() استفاده می‌کنیم. دقت کنید که پوشه مقصد نباید از قبل وجود داشته باشد؛ این متد پوشه مقصد را خودش ایجاد می‌کند.

# کپی کردن پوشه تصاویر به مقصد جدید
shutil.copytree('my_images', 'backup_images')

# کپی پوشه با نادیده گرفتن فایل‌های موقتی یا لاگ‌ها
shutil.copytree('project', 'project_backup', ignore=shutil.ignore_patterns('*.log', '*.tmp'))
متد کپی در shutil کاربرد اصلی و رفتار
shutil.copyfile() فقط کپی محتوای فایل؛ مقصد باید حتماً فایل باشد. سریع است اما متادیتا را حفظ نمی‌کند.
shutil.copy() کپی فایل به فایل یا درون پوشه؛ کپی مجوزها (permissions) انجام می‌شود ولی متادیتای زمان نادیده گرفته می‌شود.
shutil.copy2() کامل‌ترین متد کپی فایل؛ علاوه بر محتوا و مجوزها، زمان ایجاد و آخرین تغییرات فایل را نیز حفظ می‌کند.
shutil.copytree() کپی کامل یک دایرکتوری به صورت درختی و بازگشتی (Recursive). قابلیت نادیده گرفتن فایل‌های خاص را دارد.

جابجایی فایل‌ها و پوشه‌ها با shutil.move

آموزش shutil در پایتون: کپی، جابجایی و حذف فایل — تصویر 2

سریع‌ترین روش جابجایی فایل در پایتون چیست؟ تابع shutil.move() ایمن‌ترین متد است. اگر مبدا و مقصد روی یک درایو (پارتیشن) باشند، این متد مثل تغییر نام (Rename) عمل کرده و آنی است. اما اگر بین دو درایو مختلف باشد، ابتدا فایل را کپی کرده و سپس مبدا را حذف می‌کند.

برای مدیریت بهتر فایل‌ها و تمیز نگه داشتن پوشه‌ها، جابجایی فایل‌های دانلود شده یا فایل‌های خروجی برنامه‌ها بسیار رایج است. با متد shutil.move() هم می‌توانید نام فایل را تغییر دهید و هم آن را به مسیر دیگری بفرستید.

# جابجایی فایل به مسیر جدید با همان نام قبلی
shutil.move('report.pdf', '/home/user/documents/')

# جابجایی فایل و تغییر نام همزمان آن
shutil.move('draft_v1.docx', '/home/user/documents/final_report.docx')
نکته فنی مهم: اگر از shutil.move() برای جابجایی پوشه‌ها استفاده کنید و پوشه مقصد از قبل حاوی پوشه‌ای هم‌نام باشد، متد خطا صادر می‌کند یا پوشه مبدا را به درون پوشه مقصد کپی می‌کند. قبل از جابجایی پوشه‌ها، از خالی بودن یا وجود نداشتن پوشه مقصد اطمینان حاصل کنید.

حذف کامل پوشه‌ها با shutil.rmtree

آموزش shutil در پایتون: کپی، جابجایی و حذف فایل — تصویر 3

چگونه یک پوشه پر از فایل را در پایتون حذف کنیم؟ متد استاندارد os.rmdir() فقط پوشه‌های خالی را پاک می‌کند. برای حذف کل یک پوشه و تمامی فایل‌ها و زیرپوشه‌های درون آن، باید از متد shutil.rmtree() استفاده کنید که عملیات حذف را به صورت بازگشتی انجام می‌دهد.

# حذف کامل یک پوشه و محتویات آن بدون بازگشت
shutil.rmtree('old_temp_folder')

توجه داشته باشید که این متد فایل‌ها را به سطل زباله (Recycle Bin) منتقل نمی‌کند؛ بلکه آن‌ها را به صورت دائمی از روی هارد دیسک پاک می‌کند. پس در زمان استفاده از آن، متغیرها و آدرس مسیرها را به دقت بررسی کنید تا اشتباهاً داده‌های حیاتی خود را از دست ندهید.

فشرده‌سازی و آرشیو کردن فایل‌ها (ساخت فایل Zip و Tar)

یکی از بخش‌های جذاب و بسیار کاربردی shutil، توانایی فشرده‌سازی آسان پوشه‌ها است. شما بدون نیاز به کار با کتابخانه‌های پیچیده‌ای مثل zipfile یا tarfile می‌توانید به سادگی یک خط کد، عملیات فشرده‌سازی را انجام دهید.

۱. ایجاد فایل آرشیو (Zip)

با متد shutil.make_archive() می‌توانید کل یک پوشه را با فرمت‌های zip، tar، gztar و غیره فشرده کنید. برای تسلط بیشتر روی پروژه‌های نرم‌افزاری خود، مطالعه‌ی بخش تکه‌کدهای پایتون را به شما پیشنهاد می‌کنیم.

# ساخت یک فایل فشرده به نام backup.zip از پوشه project_files
shutil.make_archive('backup', 'zip', 'project_files')

۲. استخراج فایل‌های فشرده (Unpack)

برعکس عملیات بالا، استخراج محتویات یک فایل زیپ یا تار به سادگی با متد shutil.unpack_archive() امکان‌پذیر است. پایتون به صورت خودکار فرمت فایل را تشخیص داده و آن را استخراج می‌کند.

# استخراج محتویات فایل backup.zip به پوشه‌ای به نام extracted_data
shutil.unpack_archive('backup.zip', 'extracted_data')

بررسی فضای دیسک با shutil.disk_usage

چگونه ظرفیت درایوها را در پایتون بررسی کنیم؟ متد shutil.disk_usage() اطلاعات دقیقی از کل فضا (total)، فضای مصرف‌شده (used) و فضای خالی (free) یک مسیر یا درایو را بر حسب بایت به شما باز می‌گرداند.

import shutil

# بررسی فضای هارد دیسک در مسیر ریشه
total, used, free = shutil.disk_usage("/")

# تبدیل مقدار بایت به گیگابایت برای نمایش بهتر
print(f"Total: {total / (2**30):.2f} GB")
print(f"Used: {used / (2**30):.2f} GB")
print(f"Free: {free / (2**30):.2f} GB")

عیب‌یابی سریع و رفع خطاهای رایج در shutil

کار با سیستم فایل همواره ممکن است با خطاهای پیش‌بینی نشده به دلیل عدم دسترسی، پر بودن هارد دیسک یا نامعتبر بودن آدرس‌ها مواجه شود. در ادامه راه‌حل‌های عملی برای ۳ خطای پرتکرار را بررسی می‌کنیم.

  • ۱. خطای PermissionError در زمان حذف با rmtree:
    برخی فایل‌ها در ویندوز ممکن است «فقط خواندنی» (Read-only) باشند و پایتون نتواند آن‌ها را مستقیماً پاک کند. برای رفع این مشکل، از پارامتر onerror در rmtree به صورت زیر استفاده کنید:

    import os, stat, shutil
    
    def remove_readonly(func, path, excinfo):
        os.chmod(path, stat.S_IWRITE)
        func(path)
    
    shutil.rmtree('my_folder', onerror=remove_readonly)

  • ۲. خطای FileExistsError در متد copytree:
    به یاد داشته باشید که دایرکتوری مقصد در shutil.copytree() نباید وجود داشته باشد. اگر در پایتون ۳.۸ به بالا کار می‌کنید، می‌توانید با قرار دادن پارامتر dirs_exist_ok=True از بروز این خطا جلوگیری کنید تا محتویات ادغام شوند:

    shutil.copytree('src_dir', 'dest_dir', dirs_exist_ok=True)

  • ۳. خطای shutil.SameFileError:
    این خطا زمانی رخ می‌دهد که مسیر فایل مبدا و فایل مقصد دقیقاً یکسان باشد. قبل از کپی کردن، حتماً با شرط‌های منطقی چک کنید که مسیر مبدا و مقصد شما با یکدیگر متفاوت باشد.

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

۱. تفاوت بین shutil.copy و shutil.copy2 چیست؟

پاسخ: متد copy فقط محتوای فایل و دسترسی‌های اجرایی آن را کپی می‌کند، اما متد copy2 علاوه بر کپی این موارد، اطلاعات متادیتا مانند زمان دقیق ایجاد و تغییرات اخیر فایل (mtime و atime) را نیز عینا روی فایل مقصد اعمال می‌کند تا کاملاً شبیه به فایل اصلی باشد.

۲. آیا shutil امکان شبیه‌سازی انتقال درایو به درایو را به صورت آنی دارد؟

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

۳. چطور در هنگام استفاده از copytree برخی فایل‌های خاص را مستثنی کنیم؟

پاسخ: شما می‌توانید از پارامتر ignore همراه با تابع داخلی shutil.ignore_patterns استفاده کنید. برای مثال، برای کپی نکردن فایل‌های با پسوند pyc یا فایل‌های سیستمی موقت، الگوهای مورد نظر خود را به این تابع معرفی می‌کنید تا نادیده گرفته شوند.

۴. آیا shutil می‌تواند فرآیند کپی را به صورت ناهمگام (Async) انجام دهد؟

پاسخ: خیر، متدهای پیش‌فرض این کتابخانه به صورت مسدودکننده (Blocking) کار می‌کنند. اگر حجم فایل‌های شما بسیار زیاد است و نمی‌خواهید برنامه قفل شود، باید از Threading، Multiprocessing یا کتابخانه‌های جانبی غیرمسدودکننده برای اجرای وظایف کپی در پس‌زمینه استفاده کنید.

Table of Contents

آخرین نوشته‌ها

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

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