如何在Python中读取超大文本文件防止内存溢出_利用with语句配合生成器逐行读取

2026-06-03 27059 日常编程

直接 open().read() 或 readlines() 会将整个大文件一次性加载进内存,导致 MemoryError;应使用 with open() as f: for line in f 逐行迭代,内存占用恒定。

为什么直接 open() 读大文件会爆内存

因为 open().read()open().readlines() 会把整个文件一次性加载进内存。一个 10GB 的日志文件,可能直接吃光几 GB 可用内存,触发 MemoryError,甚至让系统开始疯狂 swap。

根本问题不是“Python 慢”,而是你让 Python 把整本书塞进一个口袋里——口袋装不下,自然崩了。

with + for line in file 是最稳的逐行方案

with 确保文件句柄自动关闭,for line in file 底层调用的是迭代器协议,每次只从磁盘读取一行(实际是缓冲区大小的块,但逻辑上是一行),内存占用基本恒定,和文件总大小无关。

  • ✅ 正确写法:
    with open('huge.log', 'r', encoding='utf-8') as f:
        for line in f:
            process(line.strip())
  • ❌ 错误写法:f.readlines()f.read().split('\n')list(f) —— 全部会累积所有行到内存
  • ⚠️ 注意编码:超大文件常含 BOM 或混合编码,建议显式指定 encoding,否则可能在某一行卡住并抛 UnicodeDecodeError

需要跳过空行或按条件过滤时别用 readlines()

有人想“先读完再 filter”,这是典型误区。哪怕只是 [line for line in f if line.strip()],生成列表本身就会把所有匹配行暂存内存。

Python 3.14.3

微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。

  • ✅ 流式过滤(内存恒定):
    with open('data.txt') as f:
        for line in f:
            if not line.strip():
                continue
            if 'ERROR' in line:
                log_error(line)
  • ✅ 用生成器封装更清晰:
    def valid_lines(f):
        for line in f:
            stripped = line.strip()
            if stripped and not stripped.startswith('#'):
                yield stripped
    

    with open('config.txt') as f: for line in valid_lines(f): parse_config(line)

真要随机访问某一行?别硬扛,换思路

逐行读取没法 f.seek() 到第 100 万行——因为每行长度不固定。强行用 enumerate 计数遍历到那一行,时间成本高,但内存仍安全;若频繁随机查,说明文件格式或使用方式有问题。

  • ? 更合理做法:预处理生成行偏移索引(一次耗时,多次受益)
    offsets = []
    with open('log.txt', 'rb') as f:  # 二进制模式避免解码开销
        offsets.append(0)
        while f.readline():
            offsets.append(f.tell())
    # 后续用 offsets[n] + seek() 快速定位第 n 行
  • ⚠️ 避免陷阱:不要在循环里反复 f.seek(0)for line in f——这等于重读整个文件 N 次

逐行读取本身很简单,难的是意识到“我到底需不需要整份数据”。很多所谓“性能优化”,本质是拒绝把不该进内存的东西塞进去。

如何使用Python监控服务器CPU温度并邮件告警_通过psutil模块读取系统信息

psutil无法直接读取CPU温度,因其依赖系统硬件接口且Linux需lm_sensors支持、Windows/macOS完全不支持;可靠方式是用subprocess调用sensors命令解析输出,并配合邮件告警与健壮性设计。 psutil本身不提供CPU温度读取功能——它无法直接获取温度传感器数据,强行调用psutil.sensors_temperatures()在多数Linux发行版(尤其是无...

如何解决Python Django项目上传大文件导致的内存溢出问题?

必须禁用FILE_UPLOAD_MAX_MEMORY_SIZE并改用流式上传:前端分块、后端用boto3/minio直传对象存储,绕过Django文件处理链路,结合Redis管理分片、环境变量配置存储后端及权限校验。 直接改用InMemoryUploadedFile的替代方案,否则Django默认会把整个上传文件塞进内存——哪怕你只打算存到磁盘或对象存储。 为什么InMemoryUploadedF...

如何在Python中将同步生成器重构为异步生成器yield?

异步生成器需用asyncdef+asyncyield,且内部只能混用await和yield,不能含同步阻塞调用;返回async_generator,须用asyncfor遍历,I/O操作需替换为异步版本(如aiofiles),CPU密集型任务应交由run_in_executor处理。 asyncdef里不能直接用yield Python的异步生成器不是给普通yield加个async就能跑通的。如果你...

如何在不重复打开关闭的情况下编辑并读取 JSON 文件(Python 教程)

本文讲解如何使用Python的seek()方法在单次文件操作中完成JSON写入与读取,避免因文件指针位置导致的解析错误,提升I/O效率与代码简洁性。 本文讲解如何使用python的`seek()`方法在单次文件操作中完成json写入与读取,避免因文件指针位置导致的解析错误,提升i/o效率与代码简洁性。 在Python中操作JSON文件时,一个常见误区是:写入后立即尝试读取,却遭遇JSONDecod...

怎样用Python读取Parquet格式的大数据文件_通过pandas与pyarrow

结论:用pandas.read_parquet()最省事,但必须指定engine="pyarrow";fastparquet功能弱、不支持嵌套类型和并行读取;读大文件需列裁剪、filters下推、use_threads=True或改用ParquetDataset分块读取。 直接说结论:用pandas.read_parquet()最省事,但背后必须指定engine="pyarrow"(默认值在新版本...

如何在Python中处理csv模块读取时的Error: line contains NULL byte?

csv.reader报“linecontainsNULLbyte”错误是因为文件含\x00空字节,常见于二进制文件误作文本打开、UTF-16保存或日志截断;需用rb模式读取、replace(b'\x00',b'')过滤后再decode和StringIO处理。 为什么csv.reader会报“linecontainsNULLbyte”错误? 这个错误不是CSV格式问题,而是文件里混入了\x00(空字...

如何使用Python Pandas处理具有不同分隔符的文本文件?

因为pd.read_csv()默认只认逗号,混合分隔符需用正则(如sep=r's+'或sep=r'[; |]+')并指定engine='python';sep=''仅切单空格,sep=None自动推断不可靠,固定宽度文件应改用read_fwf()。 用pd.read_csv()识别混合分隔符时为什么总报错? 因为pd.read_csv()默认只认逗号,遇到空格、制表符、多个连续空格或竖线(|)会直...

如何使用Python在读取文件时跳过注释行_在循环中加入if判断

应使用line.strip().startswith('#')判断并跳过注释行,配合withopen(...,encoding='utf-8-sig')避免BOM问题,封装清洗逻辑为独立函数,复杂格式应改用专用解析器。 读取文件时用ifline.startswith('#')判断跳过注释行 Python本身没有内置的“跳过注释”开关,必须手动判断每行是否为注释。最常见、最安全的方式是检查行首是否以...