You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python读取1.5GB+文件遇MemoryError,如何实现边读边拆分?

解决大文件读取MemoryError:边读边提取JPG的方案

嘿,这个坑我刚踩过!一次性把1.5GB的文件全塞进内存,内存直接顶爆太正常了——咱们换个思路,逐块读取文件,边读边找JPG的头尾标记,这样内存占用只会维持在你设置的块大小,完全不会爆。

先说说原代码的问题:tdata = f.read()会把整个文件加载到内存里,别说1.5GB,就算是几百MB的文件都可能出问题,完全没必要这么干。

下面是修改后的代码,我给你加了详细的注释,咱们一步一步看:

def extract_jpgs_from_large_file(input_path, chunk_size=1024*1024):
    # 注意:必须用bytes类型,和rb模式读取的文件内容匹配
    jpg_start = b'\xff\xd8'
    jpg_end = b'\xff\xd9'
    count = 0
    buffer = b''  # 用来处理跨块的标记(比如标记一半在上一块,一半在这一块)
    current_jpg = None  # 记录正在提取的JPG数据

    # 用with语句自动管理文件,不用手动close,更安全
    with open(input_path, 'rb') as f:
        while True:
            # 每次读1MB的块(可以根据内存情况调整,比如2MB、4MB都可以)
            chunk = f.read(chunk_size)
            if not chunk:
                # 文件读完了,检查有没有还没写完的JPG
                if current_jpg is not None:
                    count += 1
                    with open(f'extracted{count:03d}.jpg', 'wb') as fw:
                        fw.write(current_jpg)
                break

            # 把新读的块加到缓冲区里
            buffer += chunk

            # 循环处理缓冲区里的所有可能的JPG标记
            while True:
                if current_jpg is None:
                    # 还没找到JPG起始标记,先找开头
                    start_pos = buffer.find(jpg_start)
                    if start_pos == -1:
                        # 没找到起始标记,保留缓冲区最后1字节(防止标记跨块)
                        buffer = buffer[-1:]
                        break
                    else:
                        # 找到起始标记,开始收集JPG数据
                        current_jpg = buffer[start_pos:]
                        # 缓冲区剩下的部分从起始标记之后开始
                        buffer = buffer[start_pos + len(jpg_start):]
                else:
                    # 正在收集JPG数据,找结束标记
                    end_pos = buffer.find(jpg_end)
                    if end_pos == -1:
                        # 没找到结束标记,把缓冲区内容加到当前JPG,保留最后1字节防跨块
                        current_jpg += buffer
                        buffer = buffer[-1:]
                        break
                    else:
                        # 找到结束标记,完整提取一个JPG
                        current_jpg += buffer[:end_pos + len(jpg_end)]
                        count += 1
                        # 写入文件
                        with open(f'extracted{count:03d}.jpg', 'wb') as fw:
                            fw.write(current_jpg)
                        # 重置状态,处理下一个JPG
                        current_jpg = None
                        buffer = buffer[end_pos + len(jpg_end):]

# 调用函数,传入你的大文件路径
extract_jpgs_from_large_file('thumbdata3.dat')

几个关键要点你得注意:

  • Bytes类型匹配:原代码里的ss = '\xff\xd8'是字符串,和rb模式读出来的bytes不兼容,必须改成b'\xff\xd8',不然根本找不到标记!
  • 缓冲区处理:JPG的头尾标记可能跨两个块(比如上一块末尾是\xff,这一块开头是\xd8),所以要保留缓冲区的最后1字节,确保不会漏掉跨块的标记。
  • 分块大小可调:chunk_size默认是1MB,如果你内存够大,可以改成10MB,处理速度会更快;内存紧张的话,设成256KB也没问题。
  • 文件名格式修正:原代码里的extracted%d03.jpg是错误的,改成extracted%03d.jpg(或者用f-string的{count:03d}),生成的文件名会是extracted001.jpg、extracted002.jpg这样的有序格式。

如果运行过程中还有问题,比如提取的JPG打不开,大概率是标记匹配的问题,你可以打印一下缓冲区的内容排查,或者调整缓冲区保留的字节数(比如保留2字节,确保不会漏掉标记)。

内容的提问来源于stack exchange,提问作者ᾯᾯᾯ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:43:09