خواندن یک فایل

حال که بر مهارت‌های مقدّماتیِ مورد نیاز برای نوشتنِ برنامه‌های سازمان‌یافته و با کاربریِ آسان تسلّط یافته‌اید، زمانِ فکر کردن به این موضوع رسیده است که چگونه برنامه‌هایتان را از این هم مناسب‌تر و قابل استفاده‌تر کنید. در این فصل کار کردن با فایل‌ها را خواهید آموخت تا برنامه‌هایتان بتوانند حجم زیادی از داده‌ها را به سرعت تحلیل کنند. مدیریّتِ خطاها را نیز می‌آموزید تا برنامه‌ها هنگام برخورد با شرایط پیش‌بینی‌نشده از کار نیفتند. درباره‌ی استثناها خواهید آموخت: شیءهای ویژه‌ای که پایتون هنگام اجرای برنامه می‌سازد تا خطاهای رخ‌داده را مدیریّت کند. همچنین درباره‌ی ماژول json خواهید آموخت که به کمک آن می‌توانید اطّلاعات کاربر را ذخیره کنید تا با توقّف برنامه از بین نروند.

آموختنِ نحوه‌ی کار کردن با فایل‌ها و ذخیره کردنِ داده‌ها، استفاده از برنامه‌های شما را برای کاربران آسان‌تر می‌کند. کاربران می‌توانند انتخاب کنند که چه داده‌هایی را در چه زمانی وارد کنند. افراد می‌توانند برنامه‌ی شما را اجرا کنند، قدری کار انجام دهند، آن را ببندند و مدّتی بعد کار خود را از همان‌جا دوباره ادامه دهند. مدیریّت استثناها به شما کمک می‌کند تا وضعیّت‌هایی را که فایلی وجود ندارد یا دیگر مشکلاتی را که می‌توانند به از کار افتادنِ برنامه‌ی شما منجر شوند، مدیریّت کنید. این کار برنامه‌های شما را هنگام برخوردن به داده‌های نامناسب، مقاوم‌تر می‌کند، چه این داده‌ها سهواً و اشتباهاً وارد شده باشند چه حاصلِ حمله‌های مخرّبی برای خراب کردنِ برنامه‌های شما باشند. با مهارت‌هایی که در این فصل می‌آموزید، برنامه‌های خود را کاربردی‌تر، کاراتر و پایدارتر می‌کنید.

حجم بسیار زیادی داده در فایل‌های متنی موجود است. فایل‌های متنی ممکن است شامل داده‌های هواشناسی، ترافیکی، اقتصادی-اجتماعی، ادبیّات و … باشند. خواندن داده‌ها از یک فایل به ویژه در کاربردهای مربوط به تحلیلِ داده سودمند است، امّا در بسیاری از وضعیّت‌ها که در آن‌ها به تحلیل یا تغییرِ اطّلاعاتِ ذخیره‌شده در یک فایل نیاز داشته باشید هم کاربردی است. برای مثال می‌توانید برنامه‌ای بنویسید که محتویّات یک فایل متنی را می‌خواند و آن را به شکلی بازنویسی می‌کند که در یک مرورگر قابل نمایش باشد.

اوّلین گام برای کار کردن با اطّلاعاتِ داخلِ یک فایل خواندنِ آن و انتقال آن به حافظه است. می‌توانید کلّ یک فایل را یک‌جا بخوانید یا این که هر بار با یک خطّ آن کار کنید.

خواندن کامل یک فایل

برای آغاز کردن به فایلی نیاز داریم که چند خطّ متن داخلِ آن باشد. بیایید از فایلی شروع کنیم که در خود عدد پی را تا ۳۰ رقم اعشار دارد و هر ده رقم اعشار در یک خط قرار گرفته است:

1
2
3
3.1415926535
  8979323846
  2643383279

برای اجرا کردن مثال‌های پیشِ رو می‌توانید این خط‌ها را در یک ویرایشگر وارد کنید و آن را با نام pi_digits.txt ذخیره کنید یا این فایل را از منابع این کتاب به آدرس https://nostarch.com/pythoncrashcourse2e دریافت کنید. فایل را در همان پوشه‌ای ذخیره کنید که برنامه‌های این فصل را نگه می‌دارید.

این برنامه‌ای است که این فایل را باز می‌کند، آن را می‌خواند و محتویّات آن را روی صفحه چاپ می‌کند:

1
2
3
with open('pi_digits.txt') as file_object:
    contents = file_object.read()
    print(contents)

خطّ اوّل این برنامه حرف بسیاری برای گفتن دارد. با بررسی تابع open() شروع کنیم. برای کار کردن با یک فایل، حتّی برای چاپ کردن محتویّات آن، باید ابتدا آن را باز کنید تا به آن دسترسی داشته باشید. تابع open() تنها یک نشان‌وند می‌پذیرد: نام فایلی که می‌خواهید باز کنید. پایتون در پوشه‌ای به دنبال این فایل می‌گردد که برنامه‌ی در حالِ اجرای فعلی در آن ذخیره شده است. در این مثال file_reader.py در حال اجراست پس پایتون در پوشه‌ای که این فایل ذخیره شده به دنبال فایل pi_digits.txt می‌گردد. تابع open() شیءای را برمی‌گرداند که نماینده‌ی این فایل است. در اینجا open('pi_digits.txt') شیءای را برمی‌گرداند که نماینده‌ی pi_digits.txt باشد. پایتون این شیء را به file_object نسبت می‌دهد که جلوتر در این برنامه با آن کار خواهیم کرد.

کلیدواژه‌ی with بلافاصله بعد از این که دیگر نیازی به دسترسی به فایل نباشد، آن را می‌بندد. به این نکته دقّت کنید که در این برنامه open() را صدا کرده‌ایم امّا close() را نه. می‌توانستید فایل را با فراخوانی open() و close() باز و بسته کنید، امّا اگر اشکالی در برنامه‌ی شما مانع اجرا شدنِ متد close() شود، ممکن است فایل هیچ‌گاه بسته نشود. ممکن است بدیهی به نظر بیاید ولی بستنِ نامناسبِ فایل‌ها می‌تواند موجبِ از بین رفتن یا آسیب دیدن اطّلاعات شود. و اگر close() را زودتر از موعد فرابخوانید، در جایی از برنامه خود را در حال کار کردن با یک فایل بسته خواهید یافت که خود موجب خطاهای بیشتر خواهد شد. فهمیدنِ زمانِ دقیقِ بستنِ یک فایل ممکن است همیشه ساده نباشد امّا با ساختاری که اینجا نشان داده شده پایتون خود این کار را برای شما خواهد کرد. تمامِ کاری که باید بکنید این است که فایل را باز کرده و کاری که می‌خواهید با آن انجام دهید و مطمئن باشید که پایتون هر گاه که کار اجرای قطعه‌ی with به پایان رسید فایل را به طور خودکار خواهد بست.

پس از آن‌که شیء فایلیِ نماینده‌ی pi_digits.txt در اختیار بود، برنامه با استفاده از متد read() در خطّ دوم، تمام محتویّات آن را خوانده و در یک رشته‌ی بلند به نام contents ذخیره می‌کند. زمانی که مقدار contents را چاپ می‌کنیم و تمام فایل متنی را دریافت می‌کنیم:

1
2
3
3.1415926535
  8979323846
  2643383279

تنها تفاوت بین خروجی و فایلِ اصلی خطّ خالی اضافه‌ای در آخر خروجی است. این خطّ خالی به این دلیل پدیدار شده که read() هنگام رسیدن به پایان فایل یک رشته‌ی خالی برمی‌گرداند؛ این رشته‌ی خالی به صورت یک خطّ خالی نمایش داده می‌شود. اگر بخواهید این خطّ خالی را حذف کنید می‌توانید هنگام فراخوانی print()، rstrip() را به کار بگیرید:

1
2
3
with open('pi_digits.txt') as file_object:
    contents = file_object.read()
    print(contents.rstrip())

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

1
2
3
3.1415926535
  8979323846
  2643383279