循环写入文件时运行至约2/3阶段触发OSError(Errno 22)求助
生成千万级测试数据时触发OSError Errno 22问题排查与解决
问题描述
编写了一个用于生成数据库函数测试数据的脚本,需支持1至千万级行数、字符串长度8字符至2GB以上的测试数据。小数据集生成正常,但生成1000万行数据集时,写入到7660799行左右触发Errno 22的OSError,错误指向f.write语句。尝试更换文件扩展名(如txt)后问题依旧,暂未排查内存因素。运行环境为Python 3.10.0、Visual Studio Code 1.54.3、Windows 10(16GB内存)。
原代码如下:
import datetime, VarValues, re from time import sleep from os import getcwd, chdir from random import randint t0 = datetime.datetime.now() t1 = re.sub("[-:.]", "", str(t0)).replace(" ", "_")[0:15] fn = input("File prefix: ") chdir("H:/Project_DBDev/Python/Testdata") i = 0 f = open(fn + "_" + t1 + ".txt2", "w") f.write("Row Lenght Value\n") for j in range(VarValues.r): print("\n---\n" + str(j + 1) + "\n" + getcwd() + "\n") v = "" for i in range(randint(VarValues.rl,VarValues.rh)): ascii_value = randint(VarValues.al,VarValues.ah) v = v + chr(ascii_value) f.write(str(j + 1) + "\t" + str(len(v)) + "\t" + v + "\n") print("Value:\n" + v[0:9] + "...") print("\nLenght: " + str(len(v)) + "\n---\n") f.close() sleep(4) t1 = datetime.datetime.now() print("\nRuntime " + str(int(round((t1 - t0).total_seconds(), 0))) + " seconds\n") input()
VarValues配置:
# Number of rows. r = 10000000 # Lower random limit. rl = 100 # Upper random limit. rh = 1000 # Lowest ASCII. al = 97 # Highest ASCII. ah = 122
原因分析
- 文件句柄管理不当:直接用
open()打开文件后,长时间运行时缓冲区未及时刷新,累积过多数据后触发系统级参数错误(Errno 22对应无效参数)。 - 低效字符串拼接:循环中用
v = v + chr(ascii_value)拼接字符串,每次生成新字符串,大量占用内存,间接干扰文件写入操作。 - 过量控制台输出:每一行都打印大量内容,占用系统IO资源,拖慢脚本运行并影响文件写入稳定性。
解决方案
- 用
with语句管理文件:自动处理文件打开/关闭,确保缓冲区及时刷新,避免资源泄漏。 - 优化字符串生成:用
random.choices结合str.join替代循环拼接,提升效率并减少内存占用。 - 减少控制台输出:仅在关键节点打印进度,避免每一行都输出。
- 定期刷新缓冲区:循环中定期调用
flush(),确保数据及时写入磁盘。 - 检查磁盘空间:确认目标磁盘有足够空间(1000万行平均每行550字符,约需5.5GB空间)。
修改后的代码
import datetime import VarValues import re from time import sleep from os import getcwd, chdir from random import randint, choices from string import ascii_lowercase t0 = datetime.datetime.now() t1 = re.sub("[-:.]", "", str(t0)).replace(" ", "_")[0:15] fn = input("File prefix: ") chdir("H:/Project_DBDev/Python/Testdata") # 使用with语句自动管理文件,设置1MB缓冲区平衡效率与内存占用 with open(f"{fn}_{t1}.txt", "w", buffering=1024*1024) as f: f.write("Row\tLength\tValue\n") for j in range(VarValues.r): # 每10万行打印一次进度,减少控制台IO if (j + 1) % 100000 == 0: print(f"已写入 {j+1} 行 - 当前目录: {getcwd()}") # 用choices生成随机字符串,效率远高于循环拼接 str_len = randint(VarValues.rl, VarValues.rh) v = ''.join(choices(ascii_lowercase, k=str_len)) # 写入数据 f.write(f"{j+1}\t{str_len}\t{v}\n") # 每10万行刷新一次缓冲区,避免数据累积 if (j + 1) % 100000 == 0: f.flush() t1 = datetime.datetime.now() print(f"\n运行时长: {int(round((t1 - t0).total_seconds(), 0))} 秒") input()
额外说明
- 用
string.ascii_lowercase替代手动生成ASCII字符,代码更简洁不易出错。 - 移除不必要的
sleep(4),脚本结束后直接显示运行时长。
内容的提问来源于stack exchange,提问作者MarJer
相关产品推荐
相关产品推荐

