最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python開(kāi)發(fā)中使用read()讀取大文件導(dǎo)致內(nèi)存溢出問(wèn)題解決辦法

 更新時(shí)間:2026年06月03日 08:31:35   作者:深山技術(shù)宅  
在處理大型Excel文件時(shí),開(kāi)發(fā)者常遇到程序崩潰或響應(yīng)緩慢的問(wèn)題,其核心原因在于內(nèi)存溢出,這篇文章主要介紹了Python開(kāi)發(fā)中使用read()讀取大文件導(dǎo)致內(nèi)存溢出問(wèn)題的解決辦法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在 Python 中,文件讀取是最基本的操作之一。許多開(kāi)發(fā)者習(xí)慣用 f.read() 一次性將整個(gè)文件加載到內(nèi)存中,這在處理小文件時(shí)完全無(wú)礙,代碼也最為簡(jiǎn)潔。但當(dāng)文件體積增長(zhǎng)到幾百 MB 甚至幾 GB 時(shí),read() 就會(huì)成為“內(nèi)存殺手”,輕則導(dǎo)致程序運(yùn)行緩慢、系統(tǒng)卡頓,重則直接拋出 MemoryError 并使進(jìn)程被 操作系統(tǒng)強(qiáng)制終止。理解這一問(wèn)題的本質(zhì)并掌握流式讀取技術(shù),是編寫(xiě)健壯數(shù)據(jù)處理程序的基本功。

一、問(wèn)題復(fù)現(xiàn):一行read()引發(fā)的崩潰

with open('huge_log.txt', 'r') as f:
    content = f.read()
# 如果 huge_log.txt 大小為 10 GB,服務(wù)器內(nèi)存只有 8 GB,
# 程序會(huì)卡死或拋出 MemoryError

執(zhí)行上述代碼后,你可能看到:

MemoryError

或者操作系統(tǒng)直接殺死 Python 進(jìn)程(尤其在 Linux 的 OOM Killer 介入時(shí)),不會(huì)留下任何 Python 異常。即便文件恰巧小于可用內(nèi)存,read() 也會(huì)瞬間將大量數(shù)據(jù)寫(xiě)入 RAM,導(dǎo)致系統(tǒng)其他進(jìn)程被迫換出,嚴(yán)重拖慢整個(gè)環(huán)境。

二、底層原理:read()是“一口吞”

文件對(duì)象的 read(size=-1) 方法的行為是:

  • 若不傳 size 或傳入負(fù)值,讀取文件的全部剩余內(nèi)容直到 EOF。
  • 返回一個(gè)字符串(文本模式)或字節(jié)串(二進(jìn)制模式),這個(gè)對(duì)象在內(nèi)存中是連續(xù)的,其大小約等于文件的原始字節(jié)數(shù)(或稍大,因 Python 字符串內(nèi)部表示可能有額外開(kāi)銷(xiāo))。

對(duì)于大文件,這顯然要求 可用內(nèi)存 ≥ 文件大小。而實(shí)際場(chǎng)景中,處理數(shù)據(jù)往往只需要一次查看一行或一個(gè)數(shù)據(jù)塊,根本無(wú)需將全文件同時(shí)駐留內(nèi)存。

三、常見(jiàn)誤區(qū)與陷阱場(chǎng)景

1. 使用readlines()同樣危險(xiǎn)

with open('huge.csv', 'r') as f:
    lines = f.readlines()   # 同樣將所有行讀入一個(gè)列表

readlines() 一次性返回包含所有行的列表,每一行作為一個(gè)字符串,內(nèi)存占用較 read() 只有更大的份(因列表本身還有開(kāi)銷(xiāo))。

2. 對(duì)大文件使用splitlines()前先read()

content = f.read()
for line in content.splitlines():
    process(line)

這仍然要求整個(gè)文件進(jìn)入內(nèi)存,毫無(wú)改觀。

3. Pandas / JSON 等庫(kù)隱含的全量讀取

import pandas as pd
df = pd.read_csv('big_data.csv')   # 默認(rèn)一次性加載全部數(shù)據(jù)

雖然這些庫(kù)提供了分塊讀取參數(shù),但若忘記設(shè)置,同樣會(huì)遭遇內(nèi)存耗盡。

四、解決方案:流式讀取,按需加載

幸運(yùn)的是,Python 提供了多種優(yōu)雅的流式處理方式,使得內(nèi)存占用僅與單次處理的數(shù)據(jù)塊大小相關(guān),而不隨文件大小線性增長(zhǎng)。

方案一:固定大小分塊讀?。ǘM(jìn)制模式最可靠)

chunk_size = 4096  # 或 8192, 64*1024 等
with open('large_file.bin', 'rb') as f:
    while True:
        chunk = f.read(chunk_size)
        if not chunk:
            break
        # 處理 chunk (bytes)
  • 適用場(chǎng)景:處理二進(jìn)制文件,或進(jìn)行簡(jiǎn)單文本處理(但需自行處理行邊界)。
  • 優(yōu)點(diǎn):內(nèi)存占用恒定,對(duì)任何大小文件都穩(wěn)定。
  • 注意:文本模式下按字符讀取,需注意多字節(jié)字符可能被截?cái)?;一般建議在二進(jìn)制模式下處理非文本或自行解碼。

方案二:將文件對(duì)象作為迭代器(按行讀?。?/h3>

文本模式打開(kāi)的文件對(duì)象是一個(gè)可迭代對(duì)象,逐行產(chǎn)出 str

with open('huge_log.txt', 'r', encoding='utf-8') as f:
    for line in f:
        process(line)
  • 底層:文件對(duì)象內(nèi)部有一個(gè)緩沖區(qū),按需從磁盤(pán)讀取數(shù)據(jù)并按換行符分割,每次只返回一行。內(nèi)存中僅保留當(dāng)前行及少量緩沖,非常高效。
  • 適用:日志分析、CSV 初步過(guò)濾、任何基于行的文本處理。
  • 額外好處:代碼極簡(jiǎn),無(wú)需顯式循環(huán) readline()。

注意:如果行特別長(zhǎng)(例如單個(gè) JSON 對(duì)象占用一整行且高達(dá)數(shù)百 MB),逐行迭代仍可能因?yàn)閱涡羞^(guò)大而內(nèi)存暴漲。此時(shí)需切換為分塊讀取,并自行解析。

方案三:使用fileinput模塊處理多個(gè)大文件

import fileinput

with fileinput.input(files=['log1.txt', 'log2.txt'], mode='r', 
                     openhook=fileinput.hook_encoded('utf-8')) as f:
    for line in f:
        process(line)

fileinput 支持同時(shí)串聯(lián)多個(gè)文件,逐行遍歷,并自動(dòng)關(guān)閉打開(kāi)的文件。適合需要按行處理一系列大文件的場(chǎng)景,內(nèi)存開(kāi)銷(xiāo)低。

方案四:內(nèi)存映射文件——mmap

對(duì)于需要隨機(jī)訪問(wèn)部分讀取的大文件,使用 mmap 模塊將文件映射到虛擬內(nèi)存空間,操作系統(tǒng)會(huì)按需加載頁(yè)。

import mmap

with open('huge.dat', 'r+b') as f:
    with mmap.mmap(f.fileno(), 0) as m:
        # m 是一個(gè)類(lèi)似字節(jié)數(shù)組的對(duì)象,支持切片
        first_kb = m[:1024]
        # 可以通過(guò) find 等方法高效搜索
        pos = m.find(b'ERROR')
  • mmap 并不將整個(gè)文件讀入物理內(nèi)存,而是利用操作系統(tǒng)的內(nèi)存頁(yè)管理,只有實(shí)際訪問(wèn)的區(qū)域才被加載。這使得處理超大文件成為可能,且隨機(jī)訪問(wèn)性能極佳。
  • 缺點(diǎn):API 是字節(jié)級(jí)操作,對(duì)文本處理需手動(dòng)解碼;不是所有文件(如管道或網(wǎng)絡(luò)流)都支持 mmap。

方案五:利用高級(jí)庫(kù)的分塊參數(shù)

許多數(shù)據(jù)處理庫(kù)原生支持流式讀?。?/p>

  • Pandaspd.read_csv('data.csv', chunksize=10000) 返回一個(gè)迭代器,每次產(chǎn)出一個(gè)包含 chunksize 行的 DataFrame。
    for chunk in pd.read_csv('big.csv', chunksize=50000):
        # 對(duì) chunk 進(jìn)行操作
    
  • JSON:使用 ijson 庫(kù)進(jìn)行增量解析,避免將整個(gè) JSON 對(duì)象加載到內(nèi)存。
  • XMLxml.etree.ElementTreeiterparse 支持流式處理。
  • SQLAlchemy:可使用 yield_per() 分批獲取查詢(xún)結(jié)果。

五、內(nèi)存與性能對(duì)比

方法內(nèi)存占用適用場(chǎng)景復(fù)雜度
f.read()等于文件大小小文件(< 幾 MB)極簡(jiǎn)
f.readlines()大于文件大?。? 列表開(kāi)銷(xiāo))小文件讀所有行簡(jiǎn)單
for line in f約等于最長(zhǎng)行的字節(jié)數(shù)基于行的文本處理極簡(jiǎn)
分塊 f.read(chunk_size)固定為 chunk_size任意二進(jìn)制或需定界解析的文本簡(jiǎn)單
mmap恒常低內(nèi)存(頁(yè)緩存)需要隨機(jī)訪問(wèn)的巨大文件中等
pandas chunksize單塊大小表格數(shù)據(jù)分析簡(jiǎn)單

必須強(qiáng)調(diào)的是,流式讀取雖然在內(nèi)存上占據(jù)絕對(duì)優(yōu)勢(shì),但若處理邏輯需要同時(shí)知道所有數(shù)據(jù)(如全局排序、全數(shù)據(jù)集統(tǒng)計(jì)分析),則可能需要其他技術(shù)(外部排序、數(shù)據(jù)庫(kù)、采樣等),單純靠流式讀取無(wú)法解決。

六、調(diào)試與監(jiān)控

1. 使用memory_profiler分析內(nèi)存

# pip install memory_profiler
from memory_profiler import profile

@profile
def read_large():
    with open('big.txt') as f:
        return f.read()

運(yùn)行該腳本會(huì)輸出每行代碼的內(nèi)存增量,清晰地暴露 read() 的暴漲。

2. 估算文件大小

os.path.getsize() 獲取文件大小,判定是否采用流式讀?。?/p>

import os

def smart_open(path, chunk_threshold=50*1024*1024):  # 50 MB
    size = os.path.getsize(path)
    if size < chunk_threshold:
        with open(path) as f:
            return f.read()
    else:
        # 返回一個(gè)生成器,按行讀取
        with open(path) as f:
            for line in f:
                yield line

3. 操作系統(tǒng)工具

  • Linux:htop/free -m 觀察進(jìn)程內(nèi)存。
  • Windows:任務(wù)管理器。
  • psutil 庫(kù)在代碼中監(jiān)控進(jìn)程內(nèi)存:
    import psutil, os
    process = psutil.Process(os.getpid())
    print(process.memory_info().rss)  # 字節(jié)
    

七、最佳實(shí)踐總結(jié)

  • 永遠(yuǎn)不要假設(shè)文件“足夠小”。用戶(hù)輸入、生產(chǎn)環(huán)境日志可能隨時(shí)膨脹。
  • 默認(rèn)使用 for line in file 處理文本,這是 Pythonic 且安全的習(xí)慣。
  • 處理二進(jìn)制文件,使用固定大小的 while chunk := f.read(CHUNK): 循環(huán)
  • 面對(duì)結(jié)構(gòu)化數(shù)據(jù),首先查閱相關(guān)庫(kù)是否提供了流式 API(如 chunksize、iterparse)。
  • 如果函數(shù)封裝了文件讀取邏輯,應(yīng)避免返回整個(gè)文件內(nèi)容,而是返回一個(gè)生成器或文件對(duì)象本身,由調(diào)用方迭代。
  • **編寫(xiě)單元測(cè)試時(shí),用大文件(例如生成幾百 MB 的臨時(shí)文件)驗(yàn)證流式邏輯,防止重構(gòu)后退化為全量讀取。
  • 注意關(guān)閉文件和上下文管理,流式讀取時(shí)應(yīng)仍然使用 with 語(yǔ)句,確保文件描述符不泄漏。

八、結(jié)語(yǔ)

“使用 read() 讀取大文件導(dǎo)致內(nèi)存溢出”是一個(gè)從初學(xué)者到有經(jīng)驗(yàn)工程師都可能重復(fù)踩入的陷阱。它的危險(xiǎn)性在于:在測(cè)試環(huán)境和少量數(shù)據(jù)下一切正常,而在真實(shí)環(huán)境和數(shù)據(jù)量激增后瞬間崩盤(pán)。流式讀取不是高深技巧,而是 Python 文件處理的基本素養(yǎng)。將其內(nèi)化為肌肉記憶——看到 f.read() 時(shí),先問(wèn)自己:“這個(gè)文件可能有多大?” 你將因此避開(kāi)無(wú)數(shù)的痛苦故障,寫(xiě)出穩(wěn)健、可擴(kuò)展的數(shù)據(jù)處理程序。

到此這篇關(guān)于Python開(kāi)發(fā)中使用read()讀取大文件導(dǎo)致內(nèi)存溢出問(wèn)題解決的文章就介紹到這了,更多相關(guān)Python read()讀取大文件內(nèi)存溢出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python?哈希表的實(shí)現(xiàn)——字典詳解

    Python?哈希表的實(shí)現(xiàn)——字典詳解

    這篇文章主要介紹了Python?哈希表的實(shí)現(xiàn)——字典,那么今天我們就來(lái)看看哈希表的原理以及如何實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的?Python?哈希表,需要的朋友可以參考下
    2023-11-11
  • Python控制鍵盤(pán)鼠標(biāo)pynput的詳細(xì)用法

    Python控制鍵盤(pán)鼠標(biāo)pynput的詳細(xì)用法

    這篇文章主要介紹了Python控制鍵盤(pán)鼠標(biāo)pynput的詳細(xì)用法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • python實(shí)現(xiàn)微信遠(yuǎn)程控制電腦

    python實(shí)現(xiàn)微信遠(yuǎn)程控制電腦

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)微信遠(yuǎn)程控制電腦的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Django ModelForm操作及驗(yàn)證方式

    Django ModelForm操作及驗(yàn)證方式

    這篇文章主要介紹了Django ModelForm操作及驗(yàn)證方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-03-03
  • python 如何執(zhí)行控制臺(tái)命令與操作剪切板

    python 如何執(zhí)行控制臺(tái)命令與操作剪切板

    這篇文章主要介紹了python 如何執(zhí)行控制臺(tái)命令與操作剪切板,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • Python抓取數(shù)據(jù)到可視化全流程的實(shí)現(xiàn)過(guò)程

    Python抓取數(shù)據(jù)到可視化全流程的實(shí)現(xiàn)過(guò)程

    這篇文章主要介紹了Python抓取數(shù)據(jù)到可視化全流程的實(shí)現(xiàn)過(guò)程,
    2022-01-01
  • pycharm使用技巧之自動(dòng)調(diào)整代碼格式總結(jié)

    pycharm使用技巧之自動(dòng)調(diào)整代碼格式總結(jié)

    這篇文章主要給大家介紹了關(guān)于pycharm使用技巧之自動(dòng)調(diào)整代碼格式總結(jié)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Python編程快速上手的15個(gè)場(chǎng)景的示例代碼

    Python編程快速上手的15個(gè)場(chǎng)景的示例代碼

    本文為初學(xué)者提供15個(gè)簡(jiǎn)單的Python示例代碼,涵蓋了基本語(yǔ)法、數(shù)據(jù)結(jié)構(gòu)、文件操作、面向?qū)ο缶幊?、異常處理和網(wǎng)絡(luò)請(qǐng)求等內(nèi)容,幫助快速入門(mén)Python編程
    2025-11-11
  • Python實(shí)現(xiàn)文件夾整理下載

    Python實(shí)現(xiàn)文件夾整理下載

    這篇文章主要為大家詳細(xì)介紹了如何利用Python實(shí)現(xiàn)文件夾整理下載,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
    2023-09-09
  • Python切割圖片成九宮格的示例代碼

    Python切割圖片成九宮格的示例代碼

    這篇文章主要介紹了Python切割圖片成九宮格的相關(guān)知識(shí),本文通過(guò)截圖實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論

德庆县| 永登县| 房山区| 天长市| 新兴县| 广昌县| 江阴市| 丽水市| 崇礼县| 钦州市| 柳江县| 宁蒗| 剑河县| 仁怀市| 五莲县| 吉林市| 长武县| 淅川县| 栾城县| 株洲县| 曲松县| 清河县| 齐河县| 清远市| 灵山县| 烟台市| 南皮县| 江陵县| 兴安县| 林州市| 乐平市| 宁城县| 集安市| 贵州省| 澄江县| 方城县| 阳城县| 石阡县| 寿宁县| 德格县| 开封市|