Python3 mmap內(nèi)存映射文件示例解析
1. mmap內(nèi)存映射文件
建立一個(gè)文件的內(nèi)存映射將使用操作系統(tǒng)虛擬內(nèi)存來直接訪問文件系統(tǒng)上的數(shù)據(jù),而不是使用常規(guī)的I/O函數(shù)訪問數(shù)據(jù)。內(nèi)存映射通常可以提供I/O性能,因?yàn)槭褂脙?nèi)存映射是,不需要對(duì)每個(gè)訪問都建立一個(gè)單獨(dú)的系統(tǒng)調(diào)用,也不需要在緩沖區(qū)之間復(fù)制數(shù)據(jù);實(shí)際上,內(nèi)核和用戶應(yīng)用都能直接訪問內(nèi)存。
內(nèi)存映射文件可以看作是可修改的字符串或類似文件的對(duì)象,這取決于具體的需要。映射文件支持一般的文件API方法,如close()、flush()、read()、readline()、seek()、tell()和write()。它還支持字符串API,提供分片等特性以及類似find()的方法。
下面的所有示例都會(huì)使用文本文件lorem.txt,其中包含一些Lorem Ipsum。為便于參考,下面的代碼清單給出這個(gè)文件的文本。
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Donec egestas, enim et consectetuer ullamcorper, lectus ligula rutrum leo,
a elementum elit tortor eu quam. Duis tincidunt nisi ut ante. Nulla
facilisi. Sed tristique eros eu libero. Pellentesque vel
arcu. Vivamus purus orci, iaculis ac, suscipit sit amet, pulvinar eu,
lacus. Praesent placerat tortor sed nisl. Nunc blandit diam egestas
dui. Pellentesque habitant morbi tristique senectus et netus et
malesuada fames ac turpis egestas. Aliquam viverra fringilla
leo. Nulla feugiat augue eleifend nulla. Vivamus mauris. Vivamus sed
mauris in nibh placerat egestas. Suspendisse potenti. Mauris
massa. Ut eget velit auctor tortor blandit sollicitudin. Suspendisse
imperdiet justo.
1.1 讀文件
使用mmap()函數(shù)可以創(chuàng)建一個(gè)內(nèi)存映射文件。第一個(gè)參數(shù)是文件描述符,可能來自file對(duì)象的fileno()方法,也可能來自os.open()。調(diào)用者在調(diào)用mmap()之前負(fù)責(zé)打開文件,不再需要文件時(shí)要負(fù)責(zé)將其關(guān)閉。
mmap()的第二個(gè)參數(shù)是要映射的文件部分的大小(以字節(jié)為單位)。如果這個(gè)值為0,則映射整個(gè)文件。如果這個(gè)大小大于文件的當(dāng)前大小,則會(huì)擴(kuò)展該文件。
這兩個(gè)平臺(tái)都支持一個(gè)可選的關(guān)鍵字參數(shù)access。使用ACCESS_READ表示只讀訪問;ACCESS_WRITE表示“寫通過”(write-through),即對(duì)內(nèi)存的賦值直接寫入文件;ACCESS_COPY表示“寫時(shí)復(fù)制”(copy-on-write),對(duì)內(nèi)存的賦值不會(huì)寫至文件。
import mmap with open('lorem.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]) print('2nd 10 bytes via read :', m.read(10))
文件指針會(huì)跟蹤通過一個(gè)分片操作訪問的最后一個(gè)字節(jié)。在這個(gè)例子中,第一次讀之后,指針向前移動(dòng)10個(gè)字節(jié)。然后由分片操作將指針重置回文件的起點(diǎn)位置,并由分片使指針再次向前移動(dòng)10個(gè)字節(jié)。分片操作之后,再調(diào)用read()會(huì)給出文件的11~20字節(jié)。
1.2 寫文件
要建立內(nèi)存映射文件來接收更新,映射之前首先要使用模式'r+'(而不是'w')打開文件以便完成追加。然后可以使用任何改變數(shù)據(jù)的API方法(例如write()或賦值到一個(gè)分片等)。
下面的例子使用了默認(rèn)訪問模式ACCESS_WRITE,并賦值到一個(gè)分片,以原地修改某一行的一部分。
import mmap import shutil # Copy the example file shutil.copyfile('lorem.txt', 'lorem_copy.txt') word = b'consectetuer' reversed = word[::-1] print('Looking for :', word) print('Replacing with :', reversed) with open('lorem_copy.txt', 'r+') as f: with mmap.mmap(f.fileno(), 0) as m: print('Before:\n{}'.format(m.readline().rstrip())) m.seek(0) # rewind loc = m.find(word) m[loc:loc + len(word)] = reversed m.flush() m.seek(0) # rewind print('After :\n{}'.format(m.readline().rstrip())) f.seek(0) # rewind print('File :\n{}'.format(f.readline().rstrip()))
內(nèi)存的文件中第一行中間的單詞“consectetuer”將被替換。
使用訪問設(shè)置ACCESS_COPY時(shí)不會(huì)把修改寫入磁盤上的文件。
import mmap import shutil # Copy the example file shutil.copyfile('lorem.txt', 'lorem_copy.txt') word = b'consectetuer' reversed = word[::-1] with open('lorem_copy.txt', 'r+') as f: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY) as m: print('Memory Before:\n{}'.format( m.readline().rstrip())) print('File Before :\n{}\n'.format( f.readline().rstrip())) m.seek(0) # rewind loc = m.find(word) m[loc:loc + len(word)] = reversed m.seek(0) # rewind print('Memory After :\n{}'.format( m.readline().rstrip())) f.seek(0) print('File After :\n{}'.format( f.readline().rstrip()))
在這個(gè)例子中,必須單獨(dú)的回轉(zhuǎn)文件句柄和mmap句柄,因?yàn)檫@兩個(gè)對(duì)象的內(nèi)部狀態(tài)會(huì)單獨(dú)維護(hù)。
1.3 正則表達(dá)式
由于內(nèi)存映射文件就類似于一個(gè)字符串,因此也常與其他處理字符串的模塊一起使用,如正則表達(dá)式。下面的例子會(huì)找出所有包含“nulla”的句子。
import mmap import re pattern = re.compile(rb'(\.\W+)?([^.]?nulla[^.]*?\.)', re.DOTALL | re.IGNORECASE | re.MULTILINE) with open('lorem.txt', 'r') as f: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m: for match in pattern.findall(m): print(match[1].replace(b'\n', b' '))
由于這個(gè)模式包含兩個(gè)組,所以findall()的返回值是一個(gè)元組序列。print語句會(huì)找到匹配的句子,并用空格代替換行符,使各個(gè)結(jié)果都打印在同一行上。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用 tf.nn.dynamic_rnn 展開時(shí)間維度方式
今天小編就為大家分享一篇使用 tf.nn.dynamic_rnn 展開時(shí)間維度方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01Python Collatz序列實(shí)現(xiàn)過程解析
這篇文章主要介紹了Python Collatz序列實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10python腳本編輯oss文件的實(shí)現(xiàn)示例
本文主要介紹了python腳本編輯oss文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05Python使用pymysql模塊操作mysql增刪改查實(shí)例分析
這篇文章主要介紹了Python使用pymsql模塊操作mysql增刪改查,結(jié)合實(shí)例形式分析了Python使用pymsql模塊針對(duì)mysql進(jìn)行增刪改查操作的相關(guān)實(shí)現(xiàn)方法與操作注意事項(xiàng),需要的朋友可以參考下2019-12-12python爬蟲反爬之圖片驗(yàn)證功能實(shí)現(xiàn)
這篇文章主要介紹了python爬蟲反爬之圖片驗(yàn)證功能實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03