使用np.memmap读取大字节文件资源不足,流式读取报UnicodeDecodeError如何解决?
问题根因
你遇到的报错核心是误用了numpy.fromfile()接口:该方法的入参要求为文件路径字符串或文件对象,你传入的是fp.read()返回的bytes字节流对象,numpy会默认将该字节流尝试解码为UTF-8格式的文件名,遇到非UTF-8的二进制字节自然抛出解码错误。
可行解决方案
直接使用numpy.frombuffer()解析读取到的字节流即可,同时需要处理字节对齐问题:你使用的np.int16单元素占2字节,每次读取的块长度需要对齐单元素字节数,避免截断单个元素产生解析错误。
修正后的流式读取代码如下:
import numpy as np # 配置数据格式、块大小 dtype = np.int16 single_elem_size = dtype.itemsize # 单次读取2MB数据,可根据自身可用内存调整大小,越大整体读取效率越高 read_chunk_size = 1024 * 1024 * 2 # 存储上一轮读取剩余的不足单元素长度的字节 leftover_bytes = b'' with open(filename, mode='rb') as fp: while True: current_chunk = fp.read(read_chunk_size) # 读到文件末尾直接退出循环 if not current_chunk: break # 拼接上轮残留字节和当前读取的字节 total_bytes = leftover_bytes + current_chunk # 计算可完整解析为int16的有效字节长度,必须是单元素字节数的整数倍 valid_byte_len = (len(total_bytes) // single_elem_size) * single_elem_size # 解析有效字节为numpy数组 int_chunk = np.frombuffer(total_bytes[:valid_byte_len], dtype=dtype) # 存储本轮不足单元素长度的残留字节,下一轮拼接处理 leftover_bytes = total_bytes[valid_byte_len:] # 此处添加你对int_chunk的业务处理逻辑,例如统计、写入其他文件等 # process_chunk(int_chunk) # 全量读取完成后如果仍有残留字节,说明文件本身长度不是int16元素的整数倍,可按需处理 if leftover_bytes: print(f"文件末尾存在{len(leftover_bytes)}个无法解析为int16的残留字节")
该方案优势是np.frombuffer直接基于字节流解析,不会产生额外内存拷贝,性能开销极低。
替代思路
如果你读取的是标准.npy格式的numpy二进制文件,可以直接使用numpy内置的懒加载接口,无需自己实现流式读取逻辑,只会在访问对应数组切片时才加载数据到内存,不会占用过多系统资源:
import numpy as np # 只读模式懒加载大文件 arr = np.lib.format.open_memmap(filename, mode='r', dtype=np.int16) # 按需切片读取,单次读取10万条数据,可自行调整步长 for idx in range(0, len(arr), 100000): current_chunk = arr[idx: idx+100000] # 处理current_chunk
内容的提问来源于stack exchange,提问作者albusSimba
相关产品推荐
相关产品推荐

