通常在Unix系統裡有兩種操作的數據類型:內存地址和流文件(stream)。通過操作內存地址的方法涉及的操作有:pointers, malloc/free之類,而操作流文件涉及的方法有read/write/seek等系統調用或者send/recv/etc等socket操作。而mmap提供了結合上述兩種類型的操作方式。簡單來講,mmap可以創建一個內存映射(memory-mapped)類型的文件,可以直接在內存操作文件,而不需要使用通常的read,wirte這些系統I/O調用。這樣的好處是避免了操作文件是頻繁地系統調用。
內存映射(memory-mapped)可以像字符串和文件對象一樣操作,通過 mmap
來創建。
例子中采用的hello.txt文件如下:
Hello, i am Nisen,
Nice to meet you!
Goodbye.
# Unix version
class mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])
# Windows version
class mmap.mmap(fileno, length[, tagname[, access[, offset]]])
fileno是流文件的描述符,length指定映射文件到內存的bytes的長度,設置為0的話代表全部。Unix接口中的flags指定這個創建出來的mapping是否對創建的進程私有,默認是共享的。prot和access指定需要的內存保護(讀寫相關),其它參數的含義可以參照文檔。
接下來讓我們采用Unix的接口,做些實驗吧。
import mmap
with open('hello.txt', 'r') as f:
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
print m.readline()
m.close()
運行的結果如下:
Hello, i am Nisen,
python3.2以後mmap支持用with的方式操作
# New in version 3.2: Context manager support.
with open('hello.txt', 'r') as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
print('First 10 bytes via read :', m.read(10))
print('First 10 bytes via slice:', m[:10])
運行後的結果
python3 test.py
First 10 bytes via read : b'Hello, i am Nisen,\nNice to meet you!\nGoodbye.\n'
First 10 bytes via slice: b'Hello, i a'
常見的方法如下
with open('hello.txt', 'r+') as f:
# 指定訪問權限為write, 一共有3種權限指定:ACCESS_READ, ACCESS_WRITE, ACCESS_COPY
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE)
# 輸出一行
print m.readline()
# 指針重置
m.seek(0)
# 查找"Nisen"出現的第一個地方,返回索引
index = m.find('Nisen')
print index
m.seek(0)
# 直接修改內容
m[index: index+5] = "Rubby"
# 將內存中的修改存到磁盤中的文件上
m.flush()
m.seek(0)
print m.readline()
# 關閉內存映射文件
m.close()
運行結果如下:
➜ python test2.py
Hello, i am Nisen,
12
Hello, i am Rubby,
ACCESS_WRITE
,那麼會報 Permission denied
的錯誤