Openpyxl保存文件无报错但Shell重启,生成0字节损坏文件
Troubleshooting Openpyxl Save Causing Python Shell Crash & 0-Byte Excel File
我之前也碰到过类似的openpyxl保存时崩溃的问题,结合你的代码和场景,给你几个排查方向和修复建议:
1. Write-Only模式的误用是核心问题
你先通过write_only=True加载复制后的文件,修改标题后保存,接着又用常规模式重新加载修改数据——这种混合使用读写模式的操作很容易破坏Excel文件结构,甚至触发Python解释器崩溃。Write-only模式是为批量写入大量数据设计的,它不支持后续的读取/修改操作。
修复代码示例:
# 直接用默认读写模式加载复制后的文件,无需分两次操作 faylneym = f"DC{kw_num}.xlsx" paf = os.path.join(values['Browse0'], faylneym) shutil.copy2(values['Browse1'], paf) # 去掉write_only=True,用默认模式加载 dcwb = load_workbook(paf) dcws = dcwb['KW_XX'] dcws.title = str(kw) # 直接在这里填充所有数据 for x,y in enumerate(strdate, start=2): dcws[f'A{x}'].value = y for x,y in enumerate(strdate, start=12): dcws[f'A{x}'].value = y for x,y in enumerate(hours_from_eos2, start=2): dcws[f'E{x}'].value = y for x,y in enumerate(full_endlist_data.values(), start=2): dcws[f'D{x}'].value = y # 所有数据填充完成后,只调用一次保存 dcwb.save(paf) dcwb.close()
2. 用with语句管理工作簿,避免文件句柄泄漏
手动调用close()有时候会因为异常导致未执行,残留的文件句柄会和后续保存操作冲突,引发崩溃。用with语句可以自动管理工作簿的打开和关闭:
优化endlist处理代码:
with load_workbook(f"Endlist_{monat1}_2019.xlsx", data_only=True) as endlist: endlistws = endlist.active endlist_hrs = {} # 一次遍历完成数据收集,减少重复循环 for cell in endlistws['A']: if cell.value is None: continue cell_date = dateConverter(cell.value) if weeknum(cell_date) != kw_num: continue # 初始化字典键(不存在则创建) if cell_date not in endlist_hrs: endlist_hrs[cell_date] = [] # 直接添加J列的时间值 endlist_hrs[cell_date].append(czasownik(endlistws[f'J{cell.row}'].value)) # 退出with块后自动关闭工作簿,无需手动close() full_endlist_data = {k:sum(v) for (k,v) in endlist_hrs.items()}
3. 版本兼容性排查
你使用的Python 3.6.7 + openpyxl 3.0.2组合存在一些已知的兼容性bug,尤其是在处理复杂Excel模板时。建议:
- 升级openpyxl到3.1.x版本(该版本仍支持Python 3.6)
- 检查你的模板文件是否包含复杂元素(合并单元格、宏、特殊条件格式),尝试用简化版模板测试,排除格式导致的崩溃
4. 减少内存占用,避免解释器崩溃
你的原代码中两次遍历A列构建endlist_hrs,会额外消耗内存和CPU资源。上面的优化代码已经改成一次遍历完成,能有效降低内存负载,减少因内存耗尽导致的Shell重启。
内容的提问来源于stack exchange,提问作者Michał Lewandowski




