Python开发中使用read()读取大文件导致内存溢出问题解决办法

 更新时间:2026年06月03日 08:31:35   作者:深山技术宅  
在处理大型Excel文件时,开发者常遇到程序崩溃或响应缓慢的问题,其核心原因在于内存溢出,这篇文章主要介绍了Python开发中使用read()读取大文件导致内存溢出问题的解决办法,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在 Python 中,文件读取是最基本的操作之一。许多开发者习惯用 f.read() 一次性将整个文件加载到内存中,这在处理小文件时完全无碍,代码也最为简洁。但当文件体积增长到几百 MB 甚至几 GB 时,read() 就会成为“内存杀手”,轻则导致程序运行缓慢、系统卡顿,重则直接抛出 MemoryError 并使进程被 操作系统强制终止。理解这一问题的本质并掌握流式读取技术,是编写健壮数据处理程序的基本功。

一、问题复现:一行read()引发的崩溃

with open('huge_log.txt', 'r') as f:
    content = f.read()
# 如果 huge_log.txt 大小为 10 GB,服务器内存只有 8 GB,
# 程序会卡死或抛出 MemoryError

执行上述代码后,你可能看到:

MemoryError

或者操作系统直接杀死 Python 进程(尤其在 Linux 的 OOM Killer 介入时),不会留下任何 Python 异常。即便文件恰巧小于可用内存,read() 也会瞬间将大量数据写入 RAM,导致系统其他进程被迫换出,严重拖慢整个环境。

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

文件对象的 read(size=-1) 方法的行为是:

  • 若不传 size 或传入负值,读取文件的全部剩余内容直到 EOF
  • 返回一个字符串(文本模式)或字节串(二进制模式),这个对象在内存中是连续的,其大小约等于文件的原始字节数(或稍大,因 Python 字符串内部表示可能有额外开销)。

对于大文件,这显然要求 可用内存 ≥ 文件大小。而实际场景中,处理数据往往只需要一次查看一行或一个数据块,根本无需将全文件同时驻留内存。

三、常见误区与陷阱场景

1. 使用readlines()同样危险

with open('huge.csv', 'r') as f:
    lines = f.readlines()   # 同样将所有行读入一个列表

readlines() 一次性返回包含所有行的列表,每一行作为一个字符串,内存占用较 read() 只有更大的份(因列表本身还有开销)。

2. 对大文件使用splitlines()前先read()

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

这仍然要求整个文件进入内存,毫无改观。

3. Pandas / JSON 等库隐含的全量读取

import pandas as pd
df = pd.read_csv('big_data.csv')   # 默认一次性加载全部数据

虽然这些库提供了分块读取参数,但若忘记设置,同样会遭遇内存耗尽。

四、解决方案:流式读取,按需加载

幸运的是,Python 提供了多种优雅的流式处理方式,使得内存占用仅与单次处理的数据块大小相关,而不随文件大小线性增长。

方案一:固定大小分块读取(二进制模式最可靠)

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)
  • 适用场景:处理二进制文件,或进行简单文本处理(但需自行处理行边界)。
  • 优点:内存占用恒定,对任何大小文件都稳定。
  • 注意:文本模式下按字符读取,需注意多字节字符可能被截断;一般建议在二进制模式下处理非文本或自行解码。

方案二:将文件对象作为迭代器(按行读取)

文本模式打开的文件对象是一个可迭代对象,逐行产出 str

with open('huge_log.txt', 'r', encoding='utf-8') as f:
    for line in f:
        process(line)
  • 底层:文件对象内部有一个缓冲区,按需从磁盘读取数据并按换行符分割,每次只返回一行。内存中仅保留当前行及少量缓冲,非常高效。
  • 适用:日志分析、CSV 初步过滤、任何基于行的文本处理。
  • 额外好处:代码极简,无需显式循环 readline()

注意:如果行特别长(例如单个 JSON 对象占用一整行且高达数百 MB),逐行迭代仍可能因为单行过大而内存暴涨。此时需切换为分块读取,并自行解析。

方案三:使用fileinput模块处理多个大文件

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 支持同时串联多个文件,逐行遍历,并自动关闭打开的文件。适合需要按行处理一系列大文件的场景,内存开销低。

方案四:内存映射文件——mmap

对于需要随机访问部分读取的大文件,使用 mmap 模块将文件映射到虚拟内存空间,操作系统会按需加载页。

import mmap

with open('huge.dat', 'r+b') as f:
    with mmap.mmap(f.fileno(), 0) as m:
        # m 是一个类似字节数组的对象,支持切片
        first_kb = m[:1024]
        # 可以通过 find 等方法高效搜索
        pos = m.find(b'ERROR')
  • mmap 并不将整个文件读入物理内存,而是利用操作系统的内存页管理,只有实际访问的区域才被加载。这使得处理超大文件成为可能,且随机访问性能极佳。
  • 缺点:API 是字节级操作,对文本处理需手动解码;不是所有文件(如管道或网络流)都支持 mmap

方案五:利用高级库的分块参数

许多数据处理库原生支持流式读取:

  • Pandaspd.read_csv('data.csv', chunksize=10000) 返回一个迭代器,每次产出一个包含 chunksize 行的 DataFrame。
    for chunk in pd.read_csv('big.csv', chunksize=50000):
        # 对 chunk 进行操作
    
  • JSON:使用 ijson 库进行增量解析,避免将整个 JSON 对象加载到内存。
  • XMLxml.etree.ElementTreeiterparse 支持流式处理。
  • SQLAlchemy:可使用 yield_per() 分批获取查询结果。

五、内存与性能对比

方法内存占用适用场景复杂度
f.read()等于文件大小小文件(< 几 MB)极简
f.readlines()大于文件大小(+ 列表开销)小文件读所有行简单
for line in f约等于最长行的字节数基于行的文本处理极简
分块 f.read(chunk_size)固定为 chunk_size任意二进制或需定界解析的文本简单
mmap恒常低内存(页缓存)需要随机访问的巨大文件中等
pandas chunksize单块大小表格数据分析简单

必须强调的是,流式读取虽然在内存上占据绝对优势,但若处理逻辑需要同时知道所有数据(如全局排序、全数据集统计分析),则可能需要其他技术(外部排序、数据库、采样等),单纯靠流式读取无法解决。

六、调试与监控

1. 使用memory_profiler分析内存

# pip install memory_profiler
from memory_profiler import profile

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

运行该脚本会输出每行代码的内存增量,清晰地暴露 read() 的暴涨。

2. 估算文件大小

os.path.getsize() 获取文件大小,判定是否采用流式读取:

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:
        # 返回一个生成器,按行读取
        with open(path) as f:
            for line in f:
                yield line

3. 操作系统工具

  • Linux:htop/free -m 观察进程内存。
  • Windows:任务管理器。
  • psutil 库在代码中监控进程内存:
    import psutil, os
    process = psutil.Process(os.getpid())
    print(process.memory_info().rss)  # 字节
    

七、最佳实践总结

  • 永远不要假设文件“足够小”。用户输入、生产环境日志可能随时膨胀。
  • 默认使用 for line in file 处理文本,这是 Pythonic 且安全的习惯。
  • 处理二进制文件,使用固定大小的 while chunk := f.read(CHUNK): 循环
  • 面对结构化数据,首先查阅相关库是否提供了流式 API(如 chunksizeiterparse)。
  • 如果函数封装了文件读取逻辑,应避免返回整个文件内容,而是返回一个生成器或文件对象本身,由调用方迭代。
  • **编写单元测试时,用大文件(例如生成几百 MB 的临时文件)验证流式逻辑,防止重构后退化为全量读取。
  • 注意关闭文件和上下文管理,流式读取时应仍然使用 with 语句,确保文件描述符不泄漏。

八、结语

“使用 read() 读取大文件导致内存溢出”是一个从初学者到有经验工程师都可能重复踩入的陷阱。它的危险性在于:在测试环境和少量数据下一切正常,而在真实环境和数据量激增后瞬间崩盘。流式读取不是高深技巧,而是 Python 文件处理的基本素养。将其内化为肌肉记忆——看到 f.read() 时,先问自己:“这个文件可能有多大?” 你将因此避开无数的痛苦故障,写出稳健、可扩展的数据处理程序。

到此这篇关于Python开发中使用read()读取大文件导致内存溢出问题解决的文章就介绍到这了,更多相关Python read()读取大文件内存溢出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Numpy之random函数使用学习

    Numpy之random函数使用学习

    这篇文章主要介绍了Numpy之random使用学习,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • 详解Python中图像边缘检测算法的实现

    详解Python中图像边缘检测算法的实现

    这篇文章主要为大家详细介绍了python中图像边缘检测算法的原理及实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 利用Python将分组文本转为Excel的流程步骤

    利用Python将分组文本转为Excel的流程步骤

    在英语学习过程中,我们经常会接触各种分组整理的词汇表,如果你下载了一个 .txt 格式的四级词汇表,打算分类整理后导入 Excel 学习软件中,大概率你会遇到格式杂乱、分组不清,所以本文给大家介绍了如何用 Python 脚本自动读取一份分组文本,需要的朋友可以参考下
    2025-07-07
  • Python如何实时采集Windows CPU\MEMORY\HDD使用率

    Python如何实时采集Windows CPU\MEMORY\HDD使用率

    文章介绍如何通过Python的psutil库实时获取系统CPU、内存和磁盘使用情况,包括各函数参数及返回值,并强调其在自动化运维中的应用价值
    2025-08-08
  • Django REST Framework之频率限制的使用

    Django REST Framework之频率限制的使用

    这篇文章主要介绍了Django REST Framework之频率限制的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 使用 Python ssh 远程登陆服务器的最佳方案

    使用 Python ssh 远程登陆服务器的最佳方案

    这篇文章主要介绍了使用 Python ssh 远程登陆服务器的最佳方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Python使用Spire.XLS创建柱形图和条形图

    Python使用Spire.XLS创建柱形图和条形图

    Spire.XLS for Python 提供了便捷的图表创建功能,让开发者能够仅用几行代码就创建各种专业图表,下面我们就来看看怎么使用 Spire.XLS 创建柱形图和条形图吧
    2025-07-07
  • OPCUA-Python实例

    OPCUA-Python实例

    这篇文章主要介绍了OPCUA-Python实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • Python Web框架Django的模型和数据库迁移详解

    Python Web框架Django的模型和数据库迁移详解

    Django 是一个极其强大的 Python Web 框架,它提供了许多工具和特性,能够帮助我们更快速、更便捷地构建 Web 应用,在本文中,我们将会关注 Django 中的模型(Models)和数据库迁移(Database Migrations)这两个核心概念,需要的朋友可以参考下
    2023-08-08
  • Python Setuptools的 setup.py实例详解

    Python Setuptools的 setup.py实例详解

    setup.py是一个 python 文件,它的存在表明您要安装的模块/包可能已经用 Setuptools 打包和分发,这是分发 Python 模块的标准。 它的目的是正确安装软件,本文给大家讲解Python Setuptools的 setup.py感兴趣的朋友跟随小编一起看看吧
    2022-12-12

最新评论