سیستم فایل

از PyLearn.com، دانشنامهٔ آزاد.

پرش به: ناوبری, جستجو
این نوشته (سیستم فایل) بخشی از کتاب پایتون می باشد .
نکته ها و ترفند ها ماژول ها و ابزار وابسته نمونه پروژه و برنامه پرسش و پاسخ


راحترین روش برای کار با فایل ها و انجام اعمالی چون خواندن و نوشتن فایل ها استفاده از شی file می باشد . این شی یک اتصال به فایل بر روی دیسک را ایجاد می کند . چون file یک نوع درونی (built-in) می باشد برای استفاده از آن به ماجول یا بسته خاصی نیاز نمی باشد . تمام توضیحات و مثالهای این آموزش منطبق بر سیستم عامل های هم خانواده به unix می باشد در صورتی که از سیستم عامل دیگری مانند ویندوز استفاده می کنید . احتمالا نیاز به انجام تغییراتی خواهید داشت . برای مثال برای استفاده از آدرسی دهی در کد هی پایتون و استفاده از آدرس های ویندوز باید از 2 بک اسلش استفاده گردد .

فهرست مندرجات

[ویرایش] نوشتن یک فایل متنی

مبحث فایل را با ایجاد یک فایل و نوشتن متن در داخل آن آغاز می کنیم . برای ایجاد یک فایل جدید کافی است یک شی جدید از file درست کرده و آدرس محل فایل را به آن ارسال کنید و نیز با ارسال پارامتر w امکان نوشتن در فایل را فعال کنید . توجه کنید که شی ایجاد شده تنها یک اتصال به فایل بر روی دیسک و نه خود آن می باشد . اگر شما فایلی را برای نوشتن (پارامتر w ) ایجاد کنید ولی آن فایل بررمی دیسک موجود نباشد به صورت خودکار ایجاد می گردد .

path = "/tmp/sample.txt"
>>> sample_file = file(path, "w")

اولین آرگومان مسیر و نام فایل می باشد . و آرگومان w نشان دهنده حالت نوشتاری می باشد (قصد نوشتن برروی فایل) . هنگام کار با توابع و اشیاع این نکته را به خاطر داشته باشید که می توانید به دو صورت مسیر فایل را مشخص کنید . حالت پایه یا واقعی (absolute) که در این حالت مسیر دهی باید از دایرکتوری روت آغاز گردد و حالت وابسته (relative) که مسیر واقعی و پایه از طریق مسیر وابسته ارسالی و مسیر کنونی برنامه در حال اجرا تعیین می گردد . برای مثال آدرسtmp/sample.txt/ یک آدرس واقعی و sample.txt یک مسیر وابسته می باشد . برای نوشتن بر روی فایل ایجاد شده از تابع عضو کلاس file با نام write استفاده می شود .

>>> sample_file.write("We Are here : PyLearn.com !!!\n")

چون دستور write بصورت خودکار انتهای سطر را مشخص نمی کند شما باید خودتان این کار را با استفاده از n\ انجام دهید . اگر دوباره از تابع write استفاده شود متن جدید به انتهای فایل اضافه می گردد . :

>>> sample_file.write("""
... Pythons are snakes. They eat small mammals, killing
... them by squeezing them to death.
... """)

همچنین دستور print هم توانایی نوشتن در فایل را دارد و این کار را شبیه به منطق ++C انجام می دهد :

>>> print >> sample_file, "The End."

وظیفه عملگر << انتقال خروجی از مانیتور به شی فایل می باشد . تابع print بر خلاف write در انتهای نوشته کاراکتر خط جدید را قرار می دهد که برای جلوگیری از آن می توانید از کاما در آخر دستور استفاده کنید . زمانی که کار نوشتن بر روی فایل انجام شده و اتمام یافت شما باید فایل را ببندید . احتمالا متن مورد نظر شما بصورت واقعی بر روی دیسک و فایل ذخیره نشده است ! برای بستن فایل شما فقط کافی است شی اشاره گر به فایل را حذف کنید . این کار باعث حذف فایل نمی شود ! و فقط شی اشاره کننده به فایل را از بین می برد .

>>> del sample_file

اگر شی sample_file در داخل یک تابع تعریف شده باشد با خاتمه آن تابع این شی نیز به طور خودکار حذف می گردد اما بهتر است خودتان آن را بصورت دستی انجام دهید . خواندن متن از فایل : خواندن از فایل شبیه نوشتن در آن می باشد . ابتدا یک فایل را با استفاده از ایجاد شی file باز کنید . اینبار از پارامتر r استفاده می کنیم که اولین حرف کلمه read می باشد .

>>> input = file(path , "r")

اگر فایل ارسالی توسط پارامتر path موجود نباشد پایتون یک پیغان خطا چاپ کرده و برنامه را خاتمه می دهد . با استفاده از تابع readline می توان یک خط از فایل متنی را خواند .

>>> input.readline()
'We Are here : PyLearn.com !!!\n'

همانطور که مشاهده می کنید تابع readline کل یک سطر و حتی کاراکتر n\ را نیز برگشت می دهد . با تکرار این عمل خواهید توانست بقیه متن فایل را بخوانید . همچنین از تابع read برای خواندن یکباره کل فایل استفاده می شود . این تابع کل متن فایل را که قبلا خوانده نشده را برمی گرداند یا به عبارت صحیح تر متن فایل را از محل اشاره گر فایل تا آخر آن .


>>> text = input.read()
>>> print text
Pythons are snakes. They eat small mammals, killing
them by squeezing them to death.
The end.

همانند حالت خواندن از فایل این بار هم با استفاده از تابع del فایل را ببندید . پایتون متن درون فایل را به سطرها تقسیم می کند . تابع readlines تمام متن را در یک آرایه از سطرها بر می گرداند در مثال زیر که طول هر سطر فایل را محاسبه و چاپ می کند طریقه استفاده از تابع readlines و نیز خواندن کل فایل را مشاهده می کنید :


def print_line_lengths(path):
    input = file(path)
    for line in input.readlines():
        print len(line)

اجرای تابع و خروجی آن :

>>> print_line_lengths("/tmp/sample.txt")
39
1
53
33
9

تابع نوشته شده در قطعه کد 9 را می توانستید به صورت زیر نیز بنویسید :

>>> for line in file(path):
...    print len(line)

در نسخه های قبلی پایتون از دستور open بجای file برای ایجاد یک اشاره گر به فایل استفاده می شد که تقربیا شبیه بهم می باشند .

[ویرایش] مسیر ها و دایرکتوری

یکی از مشکل های برنامه نویسی پورتابل و قابل اجرا بر روی سیستم های مختلف موجود بودن تفاوت هایی در سیستم فایل سیستم عامل های مختلف می باشد . برای مثال دارکتوری ها در ویندوز با بک اسلش (\) از هم جدا می شوند در حالی که در لینوکس از اسلش (/) استفاده می شود . خوشبختانه پایتون خودش انجام عملیات برروی مسیر ها و تبدلات آن را بسته به سیستم عامل انجام می دهد و دستورات را برحسب نوع سیستم عامل اجرا می کند این عملیات و سایر توابع مربوط با دایرکتوری ها در ماجول os قرار دارد . البته باز مشکلاتی موجود می باشد برای مثال همه دستورات موجود در ماجول os خاص یک سیستم عامل می باشند . ماجول os خودش شامل ماجول دیگری به نام path می باشد (os.path) که توابعی را برای کار با مسیر ها فراهم می کند . توابع عضو ماجول os.path : دستور join عضو ماجول path بوده و پارامتر های دریافتی خود را با علامت جدا کننده مسیر (در لینوکس اسلش) باهم ادغام می کند :

>>> import os.path
>>> os.path.join("python","examples")
'python/examples'

این تابع امکان دریافت پارامتر های بیشتر از 2 را نیز داراست . تابع بعدی split نام دارد و آدرس دریافتی را به دو بخش شاخه پدر و اصلی و آخرین عضو مسیر تقسیم و بصورت تیوپل برمی گرداند :

>>> os.path.split("/root/Python2.4/Lib")
('/root/Python2.4', 'Lib')

همانطور که گفته شد تابع split تنها اخرین عضو مسیر را جدا و هر دو را بر می گرداند . شاید شما نیاز داشتید که کل عناصر مسیر جدا شده و هر یک به تنهایی در دسترس باشند . برای اینکار خودمان تابعی می نویسم و از تابع split در آن استفاده می کنیم و هر بار آخرین عضو مسیر را جدا کرده و تا جایی پیش می رویم که به شاخه روت برسیم :

def split_fully(path):
    parent_path, name = os.path.split(path)
    if name == "":
        return (parent_path, )
    else:
        return split_fully(parent_path) + (name, )

این تابع به صورت بازگشتی نوشته شده است و هر بار متغییر name را که نام آخرین عنصر مسیر می باشد را به انتهای لیست حاوی مسیر متصل می کند . و تا جایی ادامه می دهد که مقدار آن "" باشد . تابع بعدی abspath که مخفف absolute path مسیر نسبی را دریافت کرده و آن را با مسیر فعلی برنامه در حال اجرا ادغام کرده و بر می گرداند :

>>> print os.path.abspath("Other")
/root/python/other

خروجی حاصله وابسته به مسیر جاری می باشد . تابع بعدی برای تست وجود یا عدم وجود یک مسیر بکار می رود :

>>> os.path.exists("/home")
True
>>> os.path.exists("/home/Bayazee")
False

[ویرایش] محتویات دایرکتوری

برای دریافت محتویات درون یک دایرکتوری از تابع listdir استفاده می شود ولی توجه داشته باشید که این تابع عضو کلاس os می باشد :

>>> os.listdir("/root/Desktop")
['Best', 'trash.desktop', 'manual-20030211.pdf', 'live_data_3601', 'PIC', 'Wing.desktop', 'mnt', 'temp', 'boot',
 'cdrw.py', 'KH', 'mozilla-firefox.desktop', 'Projects', 'Down', 'Text File', 'webs', 'BMP.desktop']

برای مشاهده محتویات دایرکتوری جاری عبارت "." را بعنوان مسیر تابع وارد کنید . اشارهای به چند نکته در مورد این تابع می کنیم . نتایج نام دایرکتوری ها و فایل ها می باشند و نه مسیر حقیقی آنها . پس در صورتی که به مسیر و آدرس واقعی هر یک نیاز داشتید باید از تابع join استفاده کنید . نکته دوم اینکه نوع اسامی برگشت داده شده (فایل ها یا دایرکتوری های) با این تابع قابل تشخیص نمی باشد . پس ابتدا خودمان تابعی می نویسیم که مسیر کامل هر عضو را برگرداند :


def print_dir(dir_path):
    for name in os.listdir(dir_path):
        print os.path.join(dir_path, name)

این تابع برای تک تک عناصر درون لیست برگشتی ار تابع listdir اجرا شده و با استفاده از تابع join مسیر اصلی آن را ایجاد و چاپ می کند :

>>> print_dir("/root/Desktop")
/root/Desktop/Best
/root/Desktop/trash.desktop
/root/Desktop/manual-20030211.pdf

همانند تابع isdir می توانید از تابع isfile برای تست نوع یک عنصر استفاده می شود و اگر نوع آن فایل بود مقدار True و در غیر اینصورت False برگشت داده می شود . این تابع عضو ماجول ios.path می باشد . تغییر نام ، انتقال ، کپی و حذف فایل ها : ماجول shutil حاوی توابعی برای انجام عملیات مختلف بر روی فایل ها می باشد . برای انتقال یک فایل از تابع move عضو این ماجول استفاده می شود :

>>> import shutil
>>> shutil.move("temp.txt", "/home/archive/")

در مثال بالا فایل temp.txt از مسیر جاری به داخل دایرکتوری archive منتقل می شود . تابع دیگر عضو همین ماجول برای کپی کردن فایل ها مورد استفاده قرار می گیرد :

>>> shutil.copy("important.txt", "/home/backups/")

و به همین صورت تابع remove برای حذف فایل مورد استفاده قرار می گیرد .

>>> shutil.remove("junk.dat")

[ویرایش] ایجاد و انتقال دایرکتوری ها

ایجاد یک دایرکتوری نیز همانند سایر توابع بسیار ساده می باشد . مسیر ارسال شده برای این تابع باید موجود باشد در غیر اینصورت اجرای برنامه متوقف خواهد شد . در ضمن این تابع عضو کلاس os می باشد .

>>> os.mkdir("/tmp/python/test")

تابع شبیه دیگر makedirs می باشد که اگر مسیر درخواستی موجود نباشد آنها را نیز ایجاد می کند . برای مثال اگر در کد بالا دایرکتوری python موجود نبود امکان ایجاد test هم نبود ولی با استفاده از تابع makedirs هر دو ایجاد می گردند . برای حذف یک دایرکتوری خالی می توانید از دستور rmdir همانند mkdir استفاده کنید . اگر دایرکتوری خالی نبود ابتدا باید محتویات آن را حذف کنید . البته تابع دیگری به نام rmtree عضو ماجول shutil وجود دارد که قادر به حذف دایرکتوری پر و حذف همه محتویات آن می باشد .

[ویرایش] نکته

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