mmap --- پشتیبانی از پرونده‌های نگاشت‌شده به حافظه (memory-mapped file)


دسترس‌پذیری: not WASI.

این ماژول روی WebAssembly کار نمی‌کند یا در دسترس نیست. برای اطلاعات بیشتر، سکوهای WebAssembly را ببینید.

اشیای پرونده نگاشت‌شده به حافظه، هم مانند bytearray و هم مانند اشیای پرونده رفتار می‌کنند. شما می‌توانید از اشیای mmap در بیشتر مواردی استفاده کنید که انتظار می‌رود یک bytearray وجود داشته باشد؛ برای مثال، می‌توانید از ماژول re برای جستجو در یک پرونده نگاشت‌شده به حافظه استفاده کنید. همچنین می‌توانید یک بایت را با obj[index] = 97 تغییر دهید، یا یک زیردنباله را با انتساب به یک اسلایس تغییر دهید: obj[i1:i2] = b'...'. همچنین می‌توانید داده‌ها را از موقعیت فعلی پرونده بخوانید و بنویسید، و با seek() در پرونده به موقعیت‌های مختلف حرکت کنید.

یک پرونده نگاشت‌شده به حافظه (memory-mapped file) توسط سازنده‌ی mmap ایجاد می‌شود، که در یونیکس و ویندوز متفاوت است. در هر دو حالت، باید توصیف‌گر پرونده‌ای را که برای به‌روزرسانی باز شده است، فراهم کنید. اگر می‌خواهید یک شیء پرونده پایتون موجود را نگاشت کنید، از متد fileno() آن برای به دست آوردن مقدار صحیح پارامتر fileno استفاده کنید. در غیر این صورت، می‌توانید پرونده را با استفاده از تابع os.open() باز کنید، که توصیف‌گر پرونده را مستقیماً برمی‌گرداند (پرونده همچنان باید پس از اتمام کار بسته شود).

توجه

اگر می‌خواهید برای یک پرونده قابل‌نوشتن و بافرشده، یک نگاشت حافظه (memory-mapping) ایجاد کنید، باید ابتدا پرونده را flush() کنید. این کار برای اطمینان از اینکه تغییرات محلی در بافرها واقعاً در دسترس نگاشت باشند، ضروری است.

برای هر دو نسخه‌ی Unix و Windows از سازنده، می‌توانید access را به‌عنوان یک پارامتر کلیدواژه‌ای اختیاری مشخص کنید. access یکی از چهار مقدار را می‌پذیرد: ACCESS_READ، ACCESS_WRITE، یا ACCESS_COPY برای مشخص کردن حافظه‌ی فقط‌خواندنی، حافظه‌ی نوشتن‌همزمان (write-through) یا حافظه‌ی کپی هنگام نوشتن (copy-on-write) به‌ترتیب، یا ACCESS_DEFAULT برای واگذاری به prot. access در هر دو Unix و Windows قابل استفاده است. اگر access مشخص نشده باشد، mmap در Windows یک نگاشت نوشتن‌همزمان (write-through) برمی‌گرداند. مقدارهای اولیه‌ی حافظه برای هر سه نوع دسترسی از پرونده مشخص‌شده گرفته می‌شوند. انتساب به یک نگاشت حافظه‌ی ACCESS_READ باعث پرتاب استثنای TypeError می‌شود. انتساب به یک نگاشت حافظه‌ی ACCESS_WRITE هم بر حافظه و هم بر پرونده زیرین تأثیر می‌گذارد. انتساب به یک نگاشت حافظه‌ی ACCESS_COPY بر حافظه تأثیر می‌گذارد، اما پرونده زیرین را به‌روزرسانی نمی‌کند.

تغییر یافته در نسخه‌ی 3.7: ثابت ACCESS_DEFAULT اضافه شد.

برای نگاشت حافظه‌ی ناشناس، باید -1 به‌عنوان fileno به همراه طول ارسال شود.

class mmap.mmap(fileno, length, tagname=None, access=ACCESS_DEFAULT, offset=0)

(نسخه‌ی ویندوز) length بایت از پرونده‌ای که با دسته پرونده fileno مشخص شده است را نگاشت می‌کند و یک شیء mmap ایجاد می‌کند. اگر length بزرگ‌تر از اندازه‌ی فعلی پرونده باشد، پرونده گسترش داده می‌شود تا شامل length بایت شود. اگر length برابر 0 باشد، حداکثر طول نگاشت برابر اندازه‌ی فعلی پرونده است، مگر اینکه پرونده خالی باشد؛ در این صورت ویندوز یک استثنا پرتاب می‌کند (شما نمی‌توانید یک نگاشت خالی در ویندوز ایجاد کنید).

tagname، اگر مشخص شده باشد و None نباشد، رشته‌ای است که نام برچسب را برای نگاشت مشخص می‌کند. ویندوز به شما امکان می‌دهد نگاشت‌های متفاوت بسیاری برای یک پرونده یکسان داشته باشید. اگر نام یک برچسب موجود را مشخص کنید، آن برچسب باز می‌شود، در غیر این صورت برچسب جدیدی با این نام ایجاد می‌شود. اگر این پارامتر حذف شود یا None باشد، نگاشت بدون نام ایجاد می‌شود. اجتناب از استفاده از پارامتر tagname به قابل‌حمل نگه‌داشتن کد شما بین یونیکس و ویندوز کمک می‌کند.

offset می‌تواند به‌عنوان یک آفست از نوع عدد صحیح غیرمنفی مشخص شود. ارجاع‌های mmap نسبت به آفست از ابتدای پرونده خواهند بود. offset به‌طور پیش‌فرض ۰ است. offset باید مضربی از ALLOCATIONGRANULARITY باشد.

یک رویداد حسابرسی mmap.__new__ را با آرگومان‌های fileno، length، access، offset پرتاب می‌کند.

class mmap.mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE | PROT_READ, access=ACCESS_DEFAULT, offset=0, *, trackfd=True)

(نسخه‌ی یونیکس) length بایت از پرونده مشخص‌شده با توصیف‌گر پرونده fileno را نگاشت می‌کند و یک شیء mmap برمی‌گرداند. اگر length برابر 0 باشد، حداکثر طول نگاشت برابر اندازه‌ی فعلی پرونده در هنگام فراخوانی mmap خواهد بود.

flags ماهیت نگاشت را مشخص می‌کند. MAP_PRIVATE یک نگاشت خصوصی با کپی-در-نوشتن (copy-on-write) ایجاد می‌کند، بنابراین تغییرات در محتوای شیء mmap برای این فرایند خصوصی خواهد بود و MAP_SHARED نگاشتی ایجاد می‌کند که با تمام فرایندهای دیگری که ناحیه‌های یکسانی از پرونده را نگاشت می‌کنند، به اشتراک گذاشته می‌شود. مقدار پیش‌فرض MAP_SHARED است. برخی سیستم‌ها پرچم‌های ممکن بیشتری دارند که فهرست کامل آن‌ها در MAP_* constants مشخص شده است.

prot، در صورت مشخص شدن، محافظت دلخواه از حافظه را تعیین می‌کند؛ دو مقدار از مفیدترین مقادیر عبارتند از PROT_READ و PROT_WRITE، برای مشخص کردن اینکه صفحه‌ها می‌توانند خوانده یا نوشته شوند. prot به‌طور پیش‌فرض PROT_READ | PROT_WRITE است.

می‌توان access را به‌جای flags و prot به‌عنوان یک پارامتر کلیدواژه‌ای اختیاری مشخص کرد. مشخص کردن همزمان flags، prot و access خطا است. برای آگاهی از چگونگی استفاده از این پارامتر، توضیح access در بالا را ببینید.

می‌توان offset را به‌صورت یک آفست عدد صحیح غیرمنفی مشخص کرد. ارجاع‌های mmap نسبت به آفست از ابتدای پرونده خواهند بود. مقدار پیش‌فرض offset برابر ۰ است. offset باید مضربی از ALLOCATIONGRANULARITY باشد که در سیستم‌های یونیکس برابر PAGESIZE است.

اگر trackfd برابر False باشد، توصیف‌گر پرونده مشخص‌شده توسط fileno تکثیر نخواهد شد و شیء mmap حاصل با پرونده زیربنایی نگاشت مرتبط نخواهد بود. این بدان معناست که متدهای size() و resize() ناموفق خواهند بود. این حالت برای محدود کردن تعداد توصیف‌گرهای پرونده باز مفید است.

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

تغییر یافته در نسخه‌ی 3.13: پارامتر trackfd افزوده شد.

این مثال روش ساده‌ای برای استفاده از mmap نشان می‌دهد:

import mmap

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write(b"Hello Python!\n")

with open("hello.txt", "r+b") as f:
    # memory-map the file, size 0 means whole file
    mm = mmap.mmap(f.fileno(), 0)
    # read content via standard file methods
    print(mm.readline())  # prints b"Hello Python!\n"
    # read content via slice notation
    print(mm[:5])  # prints b"Hello"
    # update content using slice notation;
    # note that new content must have same size
    mm[6:] = b" world!\n"
    # ... and read again using standard file methods
    mm.seek(0)
    print(mm.readline())  # prints b"Hello  world!\n"
    # close the map
    mm.close()

همچنین می‌توان از mmap به‌عنوان یک مدیر زمینه در دستور with استفاده کرد:

import mmap

with mmap.mmap(-1, 13) as mm:
    mm.write(b"Hello world!")

اضافه شده در نسخه‌ی 3.2: پشتیبانی از مدیر زمینه.

مثال بعدی نحوه ایجاد یک نگاشت ناشناس (anonymous map) و مبادله داده‌ها بین فرایندهای والد و فرزند را نشان می‌دهد:

import mmap
import os

mm = mmap.mmap(-1, 13)
mm.write(b"Hello world!")

pid = os.fork()

if pid == 0:  # In a child process
    mm.seek(0)
    print(mm.readline())

    mm.close()

یک رویداد حسابرسی mmap.__new__ را با آرگومان‌های fileno، length، access، offset پرتاب می‌کند.

اشیای پرونده نگاشت‌شده به حافظه از متدهای زیر پشتیبانی می‌کنند:

close()

mmap را می‌بندد. فراخوانی‌های بعدی به سایر متدهای شیء، منجر به پرتاب استثنای ValueError خواهند شد. این کار پرونده باز را نمی‌بندد.

closed

True اگر پرونده بسته باشد.

اضافه شده در نسخه‌ی 3.2.

find(sub[, start[, end]])

کمترین اندیسی در شیء را برمی‌گرداند که زیردنباله‌ی sub در آن پیدا می‌شود، به‌گونه‌ای که sub در بازه‌ی [start، end] قرار داشته باشد. آرگومان‌های اختیاری start و end همانند نمادگذاری اسلایس تفسیر می‌شوند. در صورت شکست، -1 را برمی‌گرداند.

تغییر یافته در نسخه‌ی 3.5: اکنون bytes-like object قابل نوشتن پذیرفته می‌شود.

flush()
flush(offset, size, /)

تغییرات اعمال‌شده بر نسخه‌ی درون‌حافظه‌ای یک پرونده را به دیسک می‌نویسد. بدون استفاده از این فراخوانی، هیچ تضمینی وجود ندارد که تغییرات پیش از از بین رفتن شیء به دیسک نوشته شوند. اگر offset و size مشخص شده باشند، فقط تغییرات در محدوده‌ی مشخص‌شده از بایت‌ها به دیسک نوشته می‌شوند؛ در غیر این صورت، کل محدوده‌ی نگاشت به دیسک نوشته می‌شود. offset باید مضربی از PAGESIZE یا ALLOCATIONGRANULARITY باشد.

None برای نشان دادن موفقیت برگردانده می‌شود. در صورت شکست فراخوانی، یک استثنا پرتاب می‌شود.

تغییر یافته در نسخه‌ی 3.8: پیش‌تر، در صورت موفقیت یک مقدار غیرصفر بازگردانده می‌شد؛ در ویندوز، در صورت خطا صفر بازگردانده می‌شد. در یونیکس، در صورت موفقیت یک مقدار صفر بازگردانده می‌شد؛ در صورت خطا یک استثنا پرتاب می‌شد.

madvise(option[, start[, length]])

توصیه‌ی option را درباره‌ی ناحیه‌ی حافظه‌ای که از start شروع می‌شود و به طول length بایت ادامه دارد، به هسته ارسال کنید. option باید یکی از ثابت‌های MADV_* موجود در سیستم باشد. اگر start و length حذف شوند، کل نگاشت پوشش داده می‌شود. در برخی سیستم‌ها (از جمله لینوکس)، start باید مضربی از PAGESIZE باشد.

دسترس‌پذیری: سیستم‌های دارای فراخوان سیستمی madvise().

اضافه شده در نسخه‌ی 3.8.

move(dest, src, count)

count بایت را که از آفست src شروع می‌شوند، به اندیس مقصد dest کپی می‌کند. اگر mmap با ACCESS_READ ایجاد شده باشد، فراخوانی‌های move یک استثنای TypeError پرتاب خواهند کرد.

read([n])

یک bytes حاوی حداکثر n بایت را برمی‌گرداند که از موقعیت فعلی پرونده شروع می‌شود. اگر آرگومان حذف شده باشد، None باشد یا منفی باشد، همه بایت‌ها را از موقعیت فعلی پرونده تا انتهای نگاشت برمی‌گرداند. موقعیت پرونده به‌روزرسانی می‌شود تا به بعد از بایت‌های برگردانده‌شده اشاره کند.

تغییر یافته در نسخه‌ی 3.3: آرگومان می‌تواند حذف شود یا None باشد.

read_byte()

یک بایت در موقعیت فعلی پرونده را به‌عنوان یک عدد صحیح برمی‌گرداند و موقعیت پرونده را ۱ واحد جلو می‌برد.

readline()

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

resize(newsize)

اندازه‌ی نگاشت و پرونده زیربنایی را، در صورت وجود، تغییر می‌دهد.

تغییر اندازه‌ی نگاشتی که با access برابر با ACCESS_READ یا ACCESS_COPY ایجادشده است، باعث پرتاب یک استثنای TypeError می‌شود. تغییر اندازه‌ی نگاشتی که با تنظیم trackfd روی False ایجادشده است، باعث پرتاب یک استثنای ValueError می‌شود.

در ویندوز: تغییر اندازه‌ی نگاشت (map) در صورتی که نگاشت‌های دیگری بر روی همان پرونده نام‌دار وجود داشته باشند، باعث پرتاب یک OSError می‌شود. تغییر اندازه‌ی یک نگاشت ناشناس (یعنی بر روی پرونده صفحه‌بندی (pagefile)) بدون هیچ پیامی یک نگاشت جدید با داده‌های اصلی کپی‌شده تا طول اندازه‌ی جدید ایجاد می‌کند.

تغییر یافته در نسخه‌ی 3.11: در صورت تلاش برای تغییر اندازه زمانی که نگاشت دیگری در اختیار گرفته شده است، به‌درستی شکست می‌خورد. امکان تغییر اندازه‌ی نگاشت ناشناس در ویندوز را فراهم می‌کند

rfind(sub[, start[, end]])

بالاترین اندیسی در شیء را برمی‌گرداند که زیردنباله sub در آن یافت می‌شود، به‌طوری که sub در بازه [start، end] قرار داشته باشد. آرگومان‌های اختیاری start و end مانند نمادگذاری اسلایس تفسیر می‌شوند. در صورت شکست، -1 را برمی‌گرداند.

تغییر یافته در نسخه‌ی 3.5: اکنون bytes-like object قابل نوشتن پذیرفته می‌شود.

seek(pos[, whence])

موقعیت فعلی پرونده را تنظیم می‌کند. آرگومان whence اختیاری است و پیش‌فرض آن os.SEEK_SET یا 0 (موقعیت‌دهی مطلق پرونده) است؛ مقادیر دیگر os.SEEK_CUR یا 1 (جابه‌جایی نسبت به موقعیت فعلی) و os.SEEK_END یا 2 (جابه‌جایی نسبت به پایان پرونده) هستند.

تغییر یافته در نسخه‌ی 3.13: موقعیت مطلق جدید به‌جای None برگردانده می‌شود.

seekable()

برمی‌گرداند که آیا پرونده از مکان‌یابی (seeking) پشتیبانی می‌کند، و مقدار بازگشتی همیشه True است.

اضافه شده در نسخه‌ی 3.13.

size()

طول پرونده را برمی‌گرداند، که می‌تواند بزرگ‌تر از اندازه‌ی ناحیه‌ی نگاشت‌شده به حافظه باشد.

tell()

موقعیت فعلی اشاره‌گر پرونده را برمی‌گرداند.

write(bytes)

بایت‌های موجود در bytes را در حافظه، در موقعیت فعلی اشاره‌گر پرونده می‌نویسد و تعداد بایت‌های نوشته‌شده را برمی‌گرداند (هرگز کمتر از len(bytes) نیست، زیرا اگر نوشتن ناموفق باشد، استثنای ValueError پرتاب خواهد شد). موقعیت پرونده به‌روزرسانی می‌شود تا به بعد از بایت‌های نوشته‌شده اشاره کند. اگر mmap با ACCESS_READ ایجاد شده باشد، نوشتن در آن استثنای TypeError را پرتاب خواهد کرد.

تغییر یافته در نسخه‌ی 3.5: اکنون bytes-like object قابل نوشتن پذیرفته می‌شود.

تغییر یافته در نسخه‌ی 3.6: تعداد بایت‌های نوشته‌شده اکنون برگردانده می‌شود.

write_byte(byte)

عدد صحیح byte را در حافظه، در موقعیت فعلی اشاره‌گر پرونده می‌نویسد؛ موقعیت پرونده به اندازه 1 پیش می‌رود. اگر mmap با ACCESS_READ ایجاد شده باشد، نوشتن در آن باعث پرتاب استثنای TypeError می‌شود.

ثابت‌های MADV_*

mmap.MADV_NORMAL
mmap.MADV_RANDOM
mmap.MADV_SEQUENTIAL
mmap.MADV_WILLNEED
mmap.MADV_DONTNEED
mmap.MADV_REMOVE
mmap.MADV_DONTFORK
mmap.MADV_DOFORK
mmap.MADV_HWPOISON
mmap.MADV_MERGEABLE
mmap.MADV_UNMERGEABLE
mmap.MADV_SOFT_OFFLINE
mmap.MADV_HUGEPAGE
mmap.MADV_NOHUGEPAGE
mmap.MADV_DONTDUMP
mmap.MADV_DODUMP
mmap.MADV_FREE
mmap.MADV_NOSYNC
mmap.MADV_AUTOSYNC
mmap.MADV_NOCORE
mmap.MADV_CORE
mmap.MADV_PROTECT
mmap.MADV_FREE_REUSABLE
mmap.MADV_FREE_REUSE

این گزینه‌ها را می‌توان به mmap.madvise() ارسال کرد. هر گزینه‌ای در هر سامانه‌ای موجود نخواهد بود.

دسترس‌پذیری: سیستم‌های دارای فراخوان سیستمی madvise().

اضافه شده در نسخه‌ی 3.8.

ثابت‌های MAP_*

mmap.MAP_SHARED
mmap.MAP_PRIVATE
mmap.MAP_32BIT
mmap.MAP_ALIGNED_SUPER
mmap.MAP_ANON
mmap.MAP_ANONYMOUS
mmap.MAP_CONCEAL
mmap.MAP_DENYWRITE
mmap.MAP_EXECUTABLE
mmap.MAP_HASSEMAPHORE
mmap.MAP_JIT
mmap.MAP_NOCACHE
mmap.MAP_NOEXTEND
mmap.MAP_NORESERVE
mmap.MAP_POPULATE
mmap.MAP_RESILIENT_CODESIGN
mmap.MAP_RESILIENT_MEDIA
mmap.MAP_STACK
mmap.MAP_TPRO
mmap.MAP_TRANSLATED_ALLOW_EXECUTE
mmap.MAP_UNIX03

این‌ها پرچم‌های مختلفی هستند که می‌توان آن‌ها را به mmap.mmap() ارسال کرد. MAP_ALIGNED_SUPER فقط در FreeBSD در دسترس است و MAP_CONCEAL فقط در OpenBSD در دسترس است. توجه داشته باشید که برخی گزینه‌ها ممکن است در برخی سیستم‌ها وجود نداشته باشند.

تغییر یافته در نسخه‌ی 3.10: ثابت MAP_POPULATE اضافه شد.

اضافه شده در نسخه‌ی 3.11: ثابت MAP_STACK اضافه شد.

اضافه شده در نسخه‌ی 3.12: ثابت‌های MAP_ALIGNED_SUPER و MAP_CONCEAL افزوده شدند.

اضافه شده در نسخه‌ی 3.13: ثابت‌های MAP_32BIT، MAP_HASSEMAPHORE، MAP_JIT، MAP_NOCACHE، MAP_NOEXTEND، MAP_NORESERVE، MAP_RESILIENT_CODESIGN، MAP_RESILIENT_MEDIA، MAP_TPRO، MAP_TRANSLATED_ALLOW_EXECUTE و MAP_UNIX03 افزوده شدند.