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

امیرحسین بیگدلو 5 ماه قبل

 

 #  معرفی

وقتی میخواهیم در پایتون فایلی را کپی کنیم، دو راه اصلی برایمان وجود دارد: استفاده از ماژول shutil یا ماژول os. همه متد های ماژول os که ما در اینجا نشان خواهیم داد متد هایی هستند که به ما اجازه میدهند دستورات shell را از طریق کد پایتونمان اجرا کنیم، که ما از این دستورات استفاده میکنیم تا دستور copy ویندوز یا دستور cp لینوکس را اجرا کنیم.

 

متوجه خواهید شد که بسیاری از این متد ها، در هردو ماژول os و shutil، عملکرد بسیار مشابهی دارند، اما هر کدام از نظر عملکرد تفاوت بسیار کمی با یکدیگر دارند، که در ادامه توضیح داده خواهد شد.

 

 

 #  کپی فایل‌ها در پایتون با ماژول shutil

ماژول shutil چندین متد سطح بالا برای کپی فایل ها ارائه میدهد که در پایین به موارد اصلی اشاره میکنیم:

 

ویدیو مرتبط: ویدیو آموزش ماژول shutil در پایتون

 

 +  دستور copyfile

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

 

سینتکس این متد به شکل زیر است:

shutil.copyfile(src_file, dest_file, *, follow_symlinks=True)

 

برای مثال، کدی که در ادامه خواهد آمد فایل "file1.txt" را در فایل "file2.txt" کپی میکند:

import shutil

shutil.copyfile('file1.txt', 'file2.txt')

 

یکی از ویژگی‌های جالب و مفید shutil.copyfile آرگومان بولین follow_symlinks است. اگر روی False تنظیم شده باشد و فایل منبع یک symlink باشد، به جای کپی کردن فایل، یک symlink جدید ایجاد می شود.

 

 

 +  دستور copy

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

 

سینتکس به شرح زیر است:

shutil.copy(src_file, dest_file, *, follow_symlinks=True)

 

هر یک از این پارامترها مانند متد copyfile است. به عنوان مثال، کد زیر “file1.txt” را در “file3.txt” کپی می کند:

import shutil

shutil.copy('file1.txt', 'file3.txt')

 

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

 

 

 +  دستور copy2

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

shutil.copy2(src_file, dest_file, *, follow_symlinks=True)

 

باز هم این پارامترها مانند دستورات قبلی است که تا به حال به آنها اشاره کردیم.

 

برای مثال، کد زیر “file1.txt” را در “file4.txt” کپی می کند، و همچنین متادیتا فایل اصلی، “file1.txt” را هم حفظ می کند:

import shutil

shutil.copy2('file1.txt', 'file4.txt')

 

$ python copy-files.py 
$ ls -l
total 32
-rw-r--r--  1 scott  staff  91 Oct 27 11:26 copy-files.py
-rw-r--r--  1 scott  staff   6 Oct 27 11:27 file1.txt
-rw-r--r--  1 scott  staff   6 Oct 27 11:29 file3.txt
-rw-r--r--  1 scott  staff   6 Oct 27 11:27 file4.txt

 

همانطور که از اجرای کد بالا می بینیم، “file1.txt” در “file4.txt” کپی شد. با این حال، ممکن است متوجه شده باشید که تاریخ ایجاد در فایل جدید حفظ شده است، برخلاف shutil.copy که “file1.txt” را در “file3.txt” کپی کرده و به آن تاریخ ایجاد جدید می دهد.

 

 

 +  دستور copyfileobj

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

 

سینتکس به شرح زیر است:

shutil.copyfileobj(src_file_object, dest_file_object[, length])

 

معانی پارامترهای src_file_object و dest_file_object مشابه دستورات قبلی است، اما اکنون به اشیا اشاره می‌کند. پارامترِ length، اختیاری است و نشان دهنده اندازه بافر است که بافر تعداد بیت هایی است که در طول فرآیند کپی در حافظه نگهداری می شوند. این گزینه می تواند هنگام کپی فایل های بسیار بزرگ مفید باشد، زیرا می تواند روند کپی را تسریع کند و از مصرف کنترل نشده حافظه جلوگیری کند.

 

برای مثال کد زیر “file1.txt” را در “file5.txt” کپی می کند:

import shutil

filename1 = 'file1.txt'
fileA = open(filename1, 'rb')

filename2 = 'file5.txt'
fileB = open(filename2, 'wb')

shutil.copyfileobj(fileA, fileB)

 

همانطور که می بینیم، برای استفاده از copyfileobj، باید فایل ها را در حالت باینری (که قسمت “b” از “rb” و “wb” نشان دهنده آن است) باز کنیم. علاوه بر این، فایل منبع باید به عنوان قابل خواندن و فایل مقصد باید به عنوان قابل نوشتن باز شود (به ترتیب قسمت های “r” و “w”).

 

 

 #  کپی فایل‌ها در پایتون با ماژول os

ماژول os راهی برای استفاده از عملکرد سیستم عامل برای کپی کردن فایل های شما فراهم می کند. در بیشتر نمونه‌ها از اینجا به بعد مثال‌هایی را ارائه می‌دهیم که هم برای Windows و هم برای Unix کار می‌کنند. مثال ها به دلیل دستورات shell استفاده شده متفاوت هستند، بنابراین حتما به نحوه برچسب گذاری هر فراخوانی تابع در کامنت های پایتون توجه کنید.

 

ویدیو مرتبط: ویدیو آموزش ماژول os در پایتون

 

 +  دستور popen

این متد یک pipe را به/از دستور شما باز می کند. با این حال، توجه داشته باشید که این متد در پایتون 2.6 منسوخ شده است، بنابراین استفاده از آن را توصیه نمی کنیم مگر اینکه مجبور باشید. به عنوان یک جایگزین، مستندات پایتون به ما توصیه می‌کند که به جای آن از متد‌هایی از ماژول subprocess استفاده کنیم.

 

سینتکس به شرح زیر است:

os.popen(cmd[, mode[, bufsize]])

 

در اینجا مقدار بازگشتی یک آبجکت فایل است که به pipe متصل است. بسته به حالت می توان این آبجکت را از روی آن خواند یا نوشت. حالت پیش فرض 'r' است که امکان خواندن محتویات فایل را فراهم می کند.

 

مثال زیر "file1.txt" را در "file6.txt" کپی می کند:

import os

# Windows
os.popen('copy file1.txt file6.txt')

# Unix
os.popen('cp file1.txt file6.txt')

 

اجرای دستور به این شکل دقیقاً مانند این است که آن را مستقیماً از خط فرمان ترمینال خود اجرا کنید.

 

 

 +  دستور system

این متد دستور مشخص شده را در subshell اجرا می کند. که هم برای Unix و هم برای Windows موجود است.

 

 سینتکس به شرح زیر است:

os.system(command)

 

در اینجا command یک رشته است که حاوی دستور DOS یا Unix است. در مثال مد نظر ما، اینجا جایی است که دستور copy یا cp را قرار می دهیم.

 

به عنوان مثال، کد زیر "file1.txt" را در "file7.txt" کپی می کند:

import os

# Windows
os.system('copy file1.txt file7.txt')

# Unix
os.system('cp file1.txt file7.txt')

 

این فرمان مشابه دستور قبلی os.popen است که ما استفاده کردیم، اما این دستور در یک subshell اجرا می شود، به این معنی که در یک رشته(thread) جداگانه به موازات کد اجرایی شما اجرا می شود. برای صبر کردن برای تکمیل آن، باید .wait() را روی شی ای که توسط os.system برگردانده شده است فراخوانی کنید.

 

 

 #  کپی فایل‌ها در پایتون با ماژول subprocess

ماژول subprocess قصد دارد برخی از متد‌ها را در ماژول os جایگزین کند (به ویژه متدهای os.system و os.spawn)، و دو متد اصلی برای دسترسی به دستورات سیستم عامل ارائه می‌کند. این متد ها call و check_output هستند. یک بار دیگر، برای سیستم های یونیکس، دستور "copy file1.txt file2.txt" باید با "cp file1.txt file2.txt" جایگزین شود.

 

 

 +  دستور call

مستندات پایتون به ما توصیه می کند که از متد call برای راه اندازی یک فرمان از سیستم عامل استفاده کنیم.

 

 سینتکس به شرح زیر است:

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

 

پارامتر args شامل فرمان shell ما خواهد بود. با این حال، باید احتیاط کرد، زیرا اسناد پایتون به ما هشدار می دهد که استفاده از shell=True می تواند یک خطر امنیتی باشد.

 

 با استفاده از این فراخوانی تابع، می توانیم دستور کپی خود را به صورت زیر اجرا کنیم:

import subprocess

# Windows
status = subprocess.call('copy file1.txt file8.txt', shell=True)

# Unix
status = subprocess.call('cp file1.txt file8.txt', shell=True)

 

همانطور که مثال بالا نشان می دهد، ما به سادگی باید مانند قبل یک رشته را به دستور shell ارسال کنیم.  و همانطور که انتظار می رود، سیستم عامل "file1.txt" را در فایلی به نام "file8.txt" کپی می کند.

 

 

 +  دستور check_output

این متد همچنین به ما اجازه می دهد تا یک دستور را در یک shell اجرا کنیم. این بسیار شبیه دستور subprocess.run است، با این تفاوت که به طور پیش فرض داده ها را از stdout به صورت بایت های کدگذاری شده pipe می کند.

 

 سینتکس به شرح زیر است:

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

 

در اینجا پارامتر args شامل فرمان shell است که می خواهیم استفاده کنیم. یک بار دیگر، مستندات پایتون به ما در مورد استفاده از shell=True هشدار می دهند، بنابراین از این روش با احتیاط استفاده کنید.

 

در کد زیر، "file1.txt" را با استفاده از دستور check_output به "file9.txt" کپی می کنیم:

import subprocess

# Windows
status = subprocess.check_output('copy file1.txt file9.txt', shell=True)

# Unix
status = subprocess.check_output('cp file1.txt file9.txt', shell=True)

 

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

 

 

 #  جمع بندی

پایتون راه های مختلفی را برای کپی فایل ها به ما ارائه می دهد که برخی از آنها بخشی از مجموعه متدهای داخلی پایتون هستند. برخی افراد از برخی متد های قدرتمند پایتون برای اجرای دستورات در یک shell استفاده می کنند، مانند copy یا cp.

 

مطمئن نیستید کدام یک برای شما مناسب است؟ ما در اینجا راه های مختلفی برای کپی کردن فایل ها ارائه کردیم، پس این قابل درک است. روشی که برای کپی کردن یک فایل استفاده می کنید کاملاً به شما و به نیازهای خاص شما بستگی دارد. اگرچه در بیشتر موارد یکی از دستورات shutil نیاز شما را به خوبی برآورده میکند. سعی کنید با shutil.copy2 شروع کنید و ببینید آیا آن چیزی که شما نیاز دارید را انجام می دهد یا خیر.

مطالب مشابه



مونگارد