ویژگی تصویر

کتابخانه fileinput در پایتون — مرور کامل، مثال‌ها و نکات پیشرفته

  /  پایتون   /  کتابخانه fileinput در پایتون
بنر تبلیغاتی الف

کتابخانهٔ استاندارد fileinput در پایتون ابزاری ساده و قدرتمند برای خواندن خط‌به‌خط از یک یا چند فایل یا از ورودی استاندارد (stdin) فراهم می‌کند. این ماژول برای اسکریپت‌های خط فرمان که باید محتوای چند فایل را به صورت متوالی پردازش کنند، بسیار مناسب و حافظه‌دوست است. در این مقاله به مفاهیم، توابع مهم، نمونه‌های عملی و نکات بهینه‌سازی می‌پردازیم.

چه زمانی از fileinput استفاده کنیم؟

  • وقتی می‌خواهید چند فایل را مانند یک جریان یکپارچه بخوانید.
  • وقتی نیاز به ویرایش in-place (نوشتن خروجی به‌جای فایل ورودی) دارید.
  • برای نوشتن اسکریپت‌هایی که هم از فایل و هم از stdin (پایپ) ورودی می‌پذیرند.
  • وقتی می‌خواهید به اطلاعات کمکی مانند نام فایل فعلی یا شمارهٔ خط دسترسی داشته باشید.

توابع و ویژگی‌های کلیدی

  • fileinput.input(): تابع اصلی که یک iterator از خطوط فایل‌ها بازمی‌گرداند.
  • fileinput.filename(): نام فایل فعلی که خط از آن خوانده می‌شود.
  • fileinput.lineno(): شمارهٔ خط کلی (از ابتدای اجرای input).
  • fileinput.filelineno(): شمارهٔ خط جاری در فایل فعلی.
  • fileinput.isfirstline() و fileinput.isstdin(): تشخیص خط اول هر فایل و اینکه آیا از stdin می‌آید یا خیر.
  • inplace=True: امکان ویرایش درجا با قابلیت ساخت بکاپ.
  • openhook: برای تعیین encoding یا پشتیبانی از فایل‌های فشرده (hook_encoded، hook_compressed).

مثال پایه: خواندن چند فایل

import fileinput

for line in fileinput.input(files=('file1.txt', 'file2.txt')):
    print(fileinput.filename(), fileinput.filelineno(), line, end='')

این کد دو فایل را متوالی می‌خواند و برای هر خط نام فایل و شماره خط در آن فایل را چاپ می‌کند. استفاده از end=” برای جلوگیری از اضافه شدن دو newline ضروری است چون line خودش شامل ‘n’ است.

مثال: ویرایش درجا (in-place) با پشتیبان

import fileinput

for line in fileinput.input(files=('data.txt',), inplace=True, backup='.bak'):
    print(line.replace('old', 'new'), end='')

هنگامی که inplace=True است، stdout به صورت موقت به فایل خروجی هدایت می‌شود. print خروجی را در فایل جدید می‌نویسد و در پایان فایل قدیمی با فایل جدید جایگزین می‌شود. پارامتر backup=’.bak’ فایل اصلی را با پسوند .bak نگه می‌دارد تا بازیابی ممکن باشد.

پشتیبانی از encoding و فایل‌های فشرده

import fileinput

hooks = fileinput.hook_encoded('utf-8')
for line in fileinput.input(files=('utf8.txt',), openhook=hooks):
    process(line)

در پایتون، برای باز کردن فایل‌ها با encoding خاص می‌توان از openhook استفاده کرد. همچنین fileinput.hook_compressed را برای خواندن فایل‌های فشرده (مثل .gz) می‌توان به کار برد تا ماژول به‌صورت transparente فایل را باز کند.

نمونهٔ پیشرفته: پذیرش stdin یا فایل‌ها از آرگومان

import sys
import fileinput

# اگر اسکریپت با آرگومان اجرا شود از آنها استفاده کن، وگرنه از stdin بخوان
files = sys.argv[1:] if len(sys.argv) > 1 else ('-',)
for line in fileinput.input(files):
    if fileinput.isstdin():
        # پردازش زمانی که از پایپ یا ورودی کاربر آمده
        pass
    process(line)

در این مثال ‘-‘ به‌صورت قراردادی نشان‌دهندهٔ stdin است. fileinput.isstdin() مشخص می‌کند آیا خط فعلی از stdin آمده یا از فایل.

مقایسهٔ سریع: fileinput vs باز کردن دستی فایل‌ها

ویژگیfileinputopen دستی
خواندن چند فایل متوالیساده، iterator واحدنیاز به حلقه و مدیریت دستی
حافظهخط‌به‌خط، کم‌مصرفنیز خط‌به‌خط ممکن است اما پیاده‌سازی دستی لازم است
ویرایش درجاپشتیبانی داخلی (inplace)نیاز به tempfile و مدیریت دستی
پشتیبانی از stdin و gzipبا openhook سادهنیاز به کد اضافی

نکات عملی و بهترین شیوه‌ها

  • از نام‌گذاری fileinput.input به عنوان input در کد خودداری کنید تا با تابع builtin input تداخل نکند؛ بهتر است import fileinput as fi و سپس fi.input استفاده کنید.
  • هنگام استفاده از inplace=True مراقب باشید که خروجی به صورت لحظه‌ای به فایل نوشته می‌شود؛ همیشه بکاپ بگیرید یا از سیستم کنترل نسخه استفاده کنید.
  • برای فایل‌های باینری یا حالاتی که نیاز به کنترل دقیق encoding دارید، از openhook (hook_encoded یا hook_compressed) استفاده کنید.
  • fileinput لزوماً برای همهٔ کارها بهترین نیست: اگر نیاز به random access یا خواندن چند بار فایل دارید، بهتر است فایل‌ها را در ساختار مناسب بخوانید یا از mmap استفاده کنید.
  • برای پردازش‌های بسیار حجیم که نیاز به بیشینهٔ سرعت دارد، پروفایل کنید؛ fileinput راحت و خواناست اما در برخی موارد باز کردن و خواندن مستقیم با io.BufferedReader ممکن است سریع‌تر باشد.

اشتباهات رایج و اصلاح آنها

رایج‌ترین خطاها شامل فراموش کردن end=” در print هنگام چاپ خطوط (که منجر به خطوط خالی اضافی می‌شود) و تداخل نام تابع input با builtin هستند. مثال زیر اصلاح‌شده را نشان می‌دهد:

import fileinput as fi

for line in fi.input(files=('a.txt',), inplace=True, backup='.bak'):
    # استفاده از end='' برای جلوگیری از اضافه شدن newline دوگانه
    print(line.upper(), end='')

در این نسخه از fileinput با نام مستعار fi استفاده شده و end=” نیز تنظیم شده است تا خروجی مطابق انتظار باشد.

نتیجه‌گیری و موارد کاربرد

ماژول fileinput برای نوشتن اسکریپت‌های پردازش متن که باید چند فایل یا ورودی پایپ را به صورت یک جریان بخوانند، انتخاب بسیار مناسبی است. این کتابخانه ساده، خواناست و امکانات مفیدی مانند ویرایش درجا، hooks برای encoding و ابزارهای کمکی برای دانستن نام فایل و شماره خط را فراهم می‌کند. برای عملیات بسیار حجیم یا نیازهای خاص باینری ممکن است راه‌حل‌های دیگر مفیدتر باشند؛ اما برای اغلب اسکریپت‌های خط فرمان، fileinput سرعت توسعه و اطمینان بالایی ارائه می‌دهد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: