自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

想要高效讀寫文件嗎?Python的Mmap()函數(shù)或許可以解決你的問題

開發(fā) 后端
本篇博客將詳細(xì)介紹Python中文本文件的追加和截?cái)唷ith語句原理、seek和tell方法、內(nèi)存映射文件(mmap)以及大文件分塊讀取等方面的知識(shí)點(diǎn),幫助讀者深入了解Python文件IO操作的實(shí)現(xiàn)原理和高級(jí)應(yīng)用。

文本文件的追加和截?cái)?/h2>

文件追加的概念和應(yīng)用

在某些場(chǎng)景下,我們需要對(duì)已有的文件進(jìn)行修改,常見的方式是打開文件后將新的內(nèi)容寫入,這會(huì)覆蓋掉原來的內(nèi)容。但如果想保留原文件的內(nèi)容并在其末尾添加新的內(nèi)容,就需要用到文件追加操作。文件追加是指向一個(gè)已存在的文件末尾添加新的內(nèi)容,并且不影響原先的內(nèi)容。

使用 a 模式打開文本文件進(jìn)行追加操作

Python中使用 open() 函數(shù)打開文件時(shí),可以通過設(shè)置文件模式參數(shù)來指定文件的操作方式。其中,a 模式表示以追加的方式打開文件,即將新的內(nèi)容添加到文件末尾。

with open('file.txt', 'a') as f:
    f.write('Hello, world!\n')

在上述代碼中,我們打開了一個(gè)名為 file.txt 的文件,并使用 a 模式將字符串 'Hello, world!\n' 寫入文件末尾。需要注意的是,在使用 a 模式時(shí),如果文件不存在,則會(huì)自動(dòng)創(chuàng)建新文件。

truncate 方法實(shí)現(xiàn)文本文件截?cái)?/h4>

除了在文件末尾追加新內(nèi)容之外,我們有時(shí)還需要對(duì)文件進(jìn)行截?cái)嗖僮鳎粗槐A粑募皫仔谢蚯皫讉€(gè)字符,而舍棄文件中后面的內(nèi)容。Python中提供了 truncate() 方法來實(shí)現(xiàn)這一功能。truncate() 方法可以指定文件的長(zhǎng)度(以字節(jié)為單位),使文件中多余的部分被刪除掉,從而實(shí)現(xiàn)文件截?cái)唷?/p>

with open('file.txt', 'r+') as f:
    f.seek(0)           # 將文件指針移到文件開頭位置
    f.truncate(10)      # 截?cái)辔募?,保留?0個(gè)字符

在上述代碼中,我們首先使用 r+ 模式打開文件,并將文件指針移到文件開頭位置,然后使用 truncate() 方法截?cái)辔募?,并指定保留文件?0個(gè)字符。需要注意的是,在使用 truncate() 方法時(shí),必須以讀寫模式打開文件,否則會(huì)拋出異常。

示例代碼

下面是一個(gè)完整的示例代碼,演示了如何使用 a 模式打開文件追加內(nèi)容,并使用 truncate() 方法截?cái)辔募?/p>

def append_and_truncate():
    with open('file.txt', 'a') as f:
        f.write('Hello, world!\n')

    with open('file.txt', 'r+') as f:
        f.seek(0)
        f.truncate(10)

    with open('file.txt', 'r') as f:
        print(f.read())

在上述代碼中,我們首先使用 a 模式打開文件 file.txt 并寫入一行文本,然后再以 r+ 模式打開同一文件進(jìn)行截?cái)嗖僮?,保留?0個(gè)字符。最后,我們以只讀模式打開文件并打印其內(nèi)容,結(jié)果應(yīng)該如下所示:

Hello, worl

with 語句原理

with 語句的作用和優(yōu)勢(shì)

with語句是Python提供的一種簡(jiǎn)化文件操作的語法結(jié)構(gòu),其作用是在文件使用完后自動(dòng)關(guān)閉文件,避免了手動(dòng)關(guān)閉文件時(shí)可能出現(xiàn)的錯(cuò)誤。除了文件操作之外,with語句還可以用于其他資源的管理,例如網(wǎng)絡(luò)連接、數(shù)據(jù)庫連接等。

with open('file.txt', 'r') as f:
    data = f.read()

在上述代碼中,我們使用 with 語句打開文件 file.txt 并讀取其中的內(nèi)容,這樣即使在處理文件過程中出現(xiàn)異常,Python也會(huì)自動(dòng)關(guān)閉文件,避免了文件資源泄露的問題??梢钥吹?,使用 with 語句可以讓代碼更加簡(jiǎn)潔和優(yōu)雅。

with 語句原理及其底層實(shí)現(xiàn)

with語句的實(shí)現(xiàn)原理是基于上下文管理器(context manager)的概念。上下文管理器是一個(gè)對(duì)象,它定義了進(jìn)入和退出某個(gè)上下文時(shí)要執(zhí)行的操作。使用 with 語句時(shí),必須將一個(gè)支持上下文管理器協(xié)議的對(duì)象傳遞給它,然后 with 語句會(huì)在進(jìn)入和退出上下文時(shí)自動(dòng)調(diào)用該對(duì)象的 enter() 和 exit() 方法。

class File:
    def __init__(self, filename):
        self.filename = filename
    
    def __enter__(self):
        print('Enter')
        self.file = open(self.filename, 'r')
        return self.file
    
    def __exit__(self, exc_type, exc_value, traceback):
        print('Exit')
        self.file.close()

with File('file.txt') as f:
    data = f.read()

在上述代碼中,我們定義了一個(gè)名為 File 的上下文管理器,并實(shí)現(xiàn)了其 enter() 和 exit() 方法。在 with 語句中使用 File 對(duì)象時(shí),Python會(huì)自動(dòng)調(diào)用其 enter() 方法打開文件,并在代碼塊執(zhí)行完畢后調(diào)用 exit() 方法關(guān)閉文件。

示例代碼

下面是一個(gè)完整的示例代碼,演示了如何使用 with 語句打開文件并讀取其中的內(nèi)容。

class File:
    def __init__(self, filename):
        self.filename = filename
    
    def __enter__(self):
        self.file = open(self.filename, 'r')
        return self.file
    
    def __exit__(self, exc_type, exc_value, traceback):
        self.file.close()

def read_file():
    with File('file.txt') as f:
        data = f.read()
        print(data)

if __name__ == '__main__':
    read_file()

在上述代碼中,我們定義了一個(gè)名為 File 的上下文管理器,并在 read_file() 函數(shù)中使用 with 語句打開文件 file.txt 并讀取其中的內(nèi)容,然后自動(dòng)關(guān)閉文件。需要注意的是,在 with 語句中打開文件時(shí),必須指定文件模式參數(shù),并且不能使用 a 模式進(jìn)行追加操作。

seek 和 tell 方法

seek 和 tell 方法的作用和區(qū)別

在Python中,文件對(duì)象提供了兩個(gè)基本方法來控制文件指針的位置:seek() 和 tell()。其中,seek() 方法用于將文件指針移到文件的任意位置,而 tell() 方法則返回當(dāng)前文件指針的位置。

with open('file.txt', 'r') as f:
    data = f.read(10)   # 讀取前10個(gè)字符
    pos = f.tell()      # 獲取當(dāng)前文件指針位置
    f.seek(0)           # 將文件指針移到文件開頭位置
    data2 = f.read(10)  # 重新讀取前10個(gè)字符

print(pos)
print(data2)

在上述代碼中,我們使用 with 語句打開文件 file.txt 并讀取其中的前10個(gè)字符,然后獲取當(dāng)前文件指針的位置,并將文件指針移到文件開頭位置,最后重新讀取前10個(gè)字符。需要注意的是,在使用 seek() 方法時(shí),必須以二進(jìn)制模式打開文件。

文件指針和偏移量的概念和使用方法

文件指針是一個(gè)表示當(dāng)前讀寫位置的指針,它指向文件中下一個(gè)要讀取或?qū)懭氲淖止?jié)的位置。在Python中,文件指針的位置可以通過 tell() 方法獲取,并且可以使用 seek() 方法將其設(shè)置為任意位置。seek() 方法接受一個(gè)整數(shù)參數(shù),代表相對(duì)于文件開頭的偏移量(以字節(jié)為單位),并可指定偏移量的起始位置(0表示文件開頭,1表示當(dāng)前位置,2表示文件末尾)。

with open('file.txt', 'r') as f:
    f.seek(5)       # 將文件指針移到第6個(gè)字符處
    data = f.read() # 從第6個(gè)字符開始讀取文件內(nèi)容

在上述代碼中,我們使用 seek() 方法將文件指針移到第6個(gè)字符處,然后讀取從該位置開始的文件內(nèi)容。

實(shí)現(xiàn)隨機(jī)訪問和修改文件內(nèi)容

由于可以通過 seek() 方法將文件指針移到文件的任意位置,因此可以實(shí)現(xiàn)隨機(jī)訪問文件內(nèi)容。例如,我們可以通過 seek() 方法將文件指針移到某一行的開頭位置,然后讀取該行的內(nèi)容。類似地,我們也可以使用 seek() 和 write() 方法來修改文件的特定位置。

with open('file.txt', 'r+') as f:
    f.seek(5)           # 將文件指針移到第6個(gè)字符處
    f.write('WORLD')    # 將字符 WORLD 插入到文件中
    f.seek(0)           # 將文件指針移到文件開頭位置
    data = f.read()     # 重新讀取文件內(nèi)容

print(data)

在上述代碼中,我們使用 r+ 模式打開文件 file.txt,并將文件指針移到第6個(gè)字符處,然后使用 write() 方法向文件中插入字符串 'WORLD'。最后,我們?cè)俅螌⑽募羔樢频轿募_頭位置并讀取文件的全部?jī)?nèi)容,輸出結(jié)果應(yīng)該為:

HelloWORLD, how are you?

示例代碼

下面是一個(gè)完整的示例代碼,演示了如何使用 seek() 和 tell() 方法實(shí)現(xiàn)隨機(jī)訪問和修改文件內(nèi)容。

def random_access():
    with open('file.txt', 'r+') as f:
        f.seek(5)
        f.write('WORLD')
        f.seek(0)
        data = f.read()
        print(data)

if __name__ == '__main__':
    random_access()

在上述代碼中,我們首先使用 r+ 模式打開文件 file.txt 并將文件指針移到第6個(gè)字符處,然后使用 write() 方法插入字符串 'WORLD'。最后,我們重新將文件指針移到文件開頭位置并讀取文件的全部?jī)?nèi)容,輸出結(jié)果應(yīng)該為:

HelloWORLD, how are you?

內(nèi)存映射文件(mmap)

mmap 的作用和優(yōu)勢(shì)

Python中提供了一種特殊的文件操作方式,稱為內(nèi)存映射文件(mmap)。內(nèi)存映射文件是一種將文件內(nèi)容映射到內(nèi)存中的技術(shù),它允許我們通過內(nèi)存來讀寫文件內(nèi)容,從而避免了頻繁訪問磁盤的開銷。同時(shí),內(nèi)存映射文件還可以讓我們像處理數(shù)組一樣高效地對(duì)文件進(jìn)行隨機(jī)訪問和修改。在處理大型二進(jìn)制文件時(shí),內(nèi)存映射文件非常有用。

mmap 原理及其底層實(shí)現(xiàn)

在Python中,使用 mmap() 函數(shù)可以將一個(gè)文件對(duì)象映射到內(nèi)存中,從而生成一個(gè)內(nèi)存映射文件對(duì)象。內(nèi)存映射文件對(duì)象具有文件對(duì)象的所有方法,例如 read()、write()、seek() 等,并且也可以像操作數(shù)組一樣進(jìn)行隨機(jī)訪問和修改。

import mmap

with open('file.bin', 'r+b') as f:
    mm = mmap.mmap(f.fileno(), 0)
    
    # 讀取前10個(gè)字節(jié)
    data1 = mm[:10]
    print(data1)
    
    # 修改前5個(gè)字節(jié)
    mm[:5] = b'Hello'
    
    # 查找字符串
    pos = mm.find(b'world')
    print(pos)
    
    # 替換字符串
    mm[pos:pos+5] = b'WORLD'
    
    # 關(guān)閉內(nèi)存映射文件
    mm.close()

在上述代碼中,我們使用 mmap() 函數(shù)將文件 file.bin 映射到內(nèi)存中,并獲取了一個(gè)內(nèi)存映射文件對(duì)象 mm。然后,我們可以像處理數(shù)組一樣對(duì)內(nèi)存映射文件進(jìn)行讀寫操作。例如,我們可以使用切片符號(hào) [:] 來讀取文件的前10個(gè)字節(jié),使用 find() 方法查找特定字符串的位置,并使用切片符號(hào)來替換字符串中的部分內(nèi)容。最后,我們調(diào)用 close() 方法關(guān)閉內(nèi)存映射文件。

注意事項(xiàng)

在使用 mmap() 函數(shù)時(shí),需要注意以下幾點(diǎn):

  1. 內(nèi)存映射文件只能用于二進(jìn)制文件的處理,不支持文本模式。
  2. 內(nèi)存映射文件是通過共享內(nèi)存實(shí)現(xiàn)的,在修改文件內(nèi)容時(shí)需要注意并發(fā)訪問問題,否則可能導(dǎo)致數(shù)據(jù)損壞或進(jìn)程掛起。
  3. 在某些操作系統(tǒng)上,如果文件長(zhǎng)度超過了可用的虛擬內(nèi)存大小,則無法創(chuàng)建內(nèi)存映射文件對(duì)象。

由于 Python 的 mmap() 函數(shù)依賴于底層操作系統(tǒng)的 mmap() 系統(tǒng)調(diào)用,因此其行為和性能可能在不同的操作系統(tǒng)上有所不同。在編寫使用 mmap() 函數(shù)的代碼時(shí),通常需要對(duì)其進(jìn)行測(cè)試和優(yōu)化,以確保其在特定平臺(tái)上的表現(xiàn)符合預(yù)期。

示例代碼

下面是一個(gè)完整的示例代碼,演示了如何使用 mmap() 函數(shù)創(chuàng)建內(nèi)存映射文件對(duì)象,并對(duì)其進(jìn)行讀寫操作。

import mmap

def memory_map():
    with open('file.bin', 'r+b') as f:
        # 將文件映射到內(nèi)存中
        mm = mmap.mmap(f.fileno(), 0)
        
        # 讀取前10個(gè)字節(jié)
        data1 = mm[:10]
        print(data1)
        
        # 修改前5個(gè)字節(jié)
        mm[:5] = b'Hello'
        
        # 查找字符串
        pos = mm.find(b'world')
        print(pos)
        
        # 替換字符串
        mm[pos:pos+5] = b'WORLD'
        
        # 關(guān)閉內(nèi)存映射文件
        mm.close()

if __name__ == '__main__':
    memory_map()

在上述代碼中,我們使用 mmap() 函數(shù)將文件 file.bin 映射到內(nèi)存中,并獲取了一個(gè)內(nèi)存映射文件對(duì)象 mm。然后,我們可以像處理數(shù)組一樣對(duì)內(nèi)存映射文件進(jìn)行讀寫操作。最后,我們調(diào)用 close() 方法關(guān)閉內(nèi)存映射文件。

大文件分塊讀取

當(dāng)需要處理大型文件時(shí),可能會(huì)遇到內(nèi)存不足的問題。為了解決這個(gè)問題,我們可以將文件分成多個(gè)塊進(jìn)行讀取和處理。這樣可以避免一次性將整個(gè)文件讀入內(nèi)存,從而降低內(nèi)存的使用量。在 Python 中,我們可以使用生成器來實(shí)現(xiàn)大文件分塊讀取。

生成器函數(shù)實(shí)現(xiàn)大文件分塊讀取

def read_in_chunks(file_obj, chunk_size=1024):
    """生成器函數(shù):分塊讀取文件"""
    while True:
        data = file_obj.read(chunk_size)
        if not data:
            break
        yield data

在上述代碼中,我們定義了一個(gè)生成器函數(shù) read_in_chunks(),該函數(shù)接受兩個(gè)參數(shù):文件對(duì)象和塊大小。在函數(shù)體內(nèi),我們使用 while 循環(huán)從文件中讀取指定大小的數(shù)據(jù)塊,并將其作為生成器對(duì)象的返回值。如果讀取完整個(gè)文件,則退出循環(huán)并返回最后一塊數(shù)據(jù)。

使用生成器函數(shù)讀取大文件

with open('large_file.txt', 'r') as f:
    for chunk in read_in_chunks(f, chunk_size=1024):
        process_data(chunk)

在上述代碼中,我們使用 with 語句打開文件 large_file.txt,并循環(huán)讀取文件的分塊數(shù)據(jù)。每次循環(huán)迭代時(shí),處理函數(shù) process_data() 將會(huì)被調(diào)用,并將當(dāng)前的數(shù)據(jù)塊作為參數(shù)傳遞進(jìn)去。這樣,在整個(gè)文件讀取完成后,我們可以在 process_data() 函數(shù)內(nèi)部處理所有的數(shù)據(jù)。

注意事項(xiàng)

需要注意以下幾點(diǎn):

  1. 在使用生成器函數(shù)處理大型文件時(shí),需要根據(jù)實(shí)際情況選擇合適的塊大小。如果塊的大小太小,則會(huì)增加系統(tǒng)的調(diào)用次數(shù);如果塊的大小太大,則可能會(huì)導(dǎo)致內(nèi)存溢出。
  2. 如果在處理文件結(jié)束后沒有顯式地關(guān)閉文件對(duì)象,則可能會(huì)導(dǎo)致資源泄漏或其他問題。
  3. 在某些操作系統(tǒng)上,如果文件長(zhǎng)度超過了可用的虛擬內(nèi)存大小,則可能無法完整讀取文件。

示例代碼

下面是一個(gè)完整的示例代碼,演示了如何使用生成器函數(shù)實(shí)現(xiàn)大文件分塊讀取。

def read_in_chunks(file_obj, chunk_size=1024):
    """生成器函數(shù):分塊讀取文件"""
    while True:
        data = file_obj.read(chunk_size)
        if not data:
            break
        yield data

def process_data(data):
    """處理函數(shù):輸出數(shù)據(jù)塊的長(zhǎng)度"""
    print(len(data))

if __name__ == '__main__':
    with open('large_file.txt', 'r') as f:
        for chunk in read_in_chunks(f, chunk_size=1024):
            process_data(chunk)

在上述代碼中,我們定義了一個(gè)生成器函數(shù) read_in_chunks(),用于分塊讀取文件;另外還定義了一個(gè)處理函數(shù) process_data(),用于輸出數(shù)據(jù)塊的長(zhǎng)度。最后,在主程序中,我們使用 with 語句打開文件 large_file.txt 并循環(huán)讀取文件的分塊數(shù)據(jù),并將其作為參數(shù)傳遞給 process_data() 函數(shù)進(jìn)行處理。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2010-03-24 12:59:27

無線上網(wǎng)信號(hào)

2018-05-28 14:38:44

PHPPython應(yīng)用

2019-07-02 13:55:50

蘋果谷歌亞馬遜

2015-12-31 10:45:25

云計(jì)算風(fēng)險(xiǎn)

2018-11-15 19:00:12

人工智能帕金森病醫(yī)學(xué)

2020-08-16 10:58:20

Pandaspython開發(fā)

2024-08-23 09:06:26

2023-09-04 07:54:06

2022-02-28 19:32:27

I/O磁盤

2019-10-15 14:14:26

Linuxshell運(yùn)維

2022-08-18 09:51:50

Python代碼循環(huán)

2011-10-09 11:08:03

EMCOpenWorld云計(jì)算

2023-12-04 07:09:53

函數(shù)遞歸python

2020-12-18 07:43:57

csv文件亂碼Python

2016-10-14 09:01:34

2023-02-28 07:39:18

2021-03-18 18:38:48

邊緣計(jì)算云計(jì)算數(shù)字化

2024-01-03 14:52:15

數(shù)字化轉(zhuǎn)型

2020-05-26 12:32:30

Python模板語言編程語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)