Openpyxl 在保存时损坏 xlsx。即使没有做出任何改变

2023-12-02

TL;DR;

  • 使用 Openpyxl 保存对大型 Excel 文件的更改会导致 xlsx 文件损坏
  • Excel 文件由多个带有图形、公式、图像和表格的选项卡组成。
  • Powershell 脚本可以毫无问题地将编辑保存到 xlsx 文件。
  • 我可以使用 Openpyxl 从 Excel 文件中读取单元格值,我还可以手动编辑和保存 xlsx 文件。
  • Excel 文件未受保护。
  • 下面提供了所有错误和代码片段。

我无法将数据添加到我们的一个团队正在使用的 Excel 文件中。 Excel 文件相当大(+3MB),有几张表,包含公式和图表,还有图像。

值得庆幸的是,我需要输入数据的工作表没有这些,但是,我发现当我尝试保存工作簿时,我最终遇到了这些错误:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    wb.save("new.xlsx")
  File "C:\Python3\lib\site-packages\openpyxl\workbook\workbook.py", line 392, in save
    save_workbook(self, filename)
  File "C:\Python3\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
    writer.save()
  File "C:\Python3\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
    self.write_data()
  File "C:\Python3\lib\site-packages\openpyxl\writer\excel.py", line 78, in write_data
    self._write_charts()
  File "C:\Python3\lib\site-packages\openpyxl\writer\excel.py", line 124, in _write_charts
    self._archive.writestr(chart.path[1:], tostring(chart._write()))
  File "C:\Python3\lib\site-packages\openpyxl\chart\_chart.py", line 134, in _write
    return cs.to_tree()
  File "C:\Python3\lib\site-packages\openpyxl\chart\chartspace.py", line 193, in to_tree
    tree = super(ChartSpace, self).to_tree()
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 154, in to_tree
    node = obj.to_tree(child_tag)
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 154, in to_tree
    node = obj.to_tree(child_tag)
  File "C:\Python3\lib\site-packages\openpyxl\chart\plotarea.py", line 135, in to_tree
    return super(PlotArea, self).to_tree(tagname)
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 146, in to_tree
    for node in nodes:
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\sequence.py", line 105, in to_tree
    el = v.to_tree(namespace=namespace)
  File "C:\Python3\lib\site-packages\openpyxl\chart\_chart.py", line 107, in to_tree
    return super(ChartBase, self).to_tree(tagname, idx)
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 146, in to_tree
    for node in nodes:
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\sequence.py", line 39, in to_tree
    el = v.to_tree(tagname, idx)
  File "C:\Python3\lib\site-packages\openpyxl\chart\series.py", line 170, in to_tree
    return super(Series, self).to_tree(tagname)
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 154, in to_tree
    node = obj.to_tree(child_tag)
  File "C:\Python3\lib\site-packages\openpyxl\descriptors\serialisable.py", line 154, in to_tree
    node = obj.to_tree(child_tag)
AttributeError: 'str' object has no attribute 'to_tree'

这是我用来执行“另存为”过程的代码,所以不要介意添加数据之类的,保存操作会损坏文件:

from openpyxl import load_workbook

wb=load_workbook("Production Monitoring Script.xlsx")
ws=wb['Prod Perf Script Data']
wb.save("new.xlsx")

我尝试了使用 Powershell 的替代解决方案,它起作用了。

$xl=New-Object -ComObject Excel.Application
$wb=$xl.WorkBooks.Open('<path here>\Production Monitoring Script.xlsx')
$ws=$wb.WorkSheets.item(1)
$xl.Visible=$true

$ws.Cells.Item(7, 618)=50

$wb.SaveAs('<path here>\New.xlsx')
$xl.Quit()

它能够在该单元格中保存值“50”。


正如原始帖子评论中所讨论的:openpyxl 不支持某些图形和其他项目,即使它们位于未由您的代码修改的工作表中。这是not完整的解决方法,但仅当不受支持的对象位于其他工作表中时才有效。

我制作了一个示例 .xlsx 工作簿,其中包含两个工作表“TWC”和“UV240 结果”。此代码假定标题以“Results”结尾的任何工作表都包含不受支持的图像,并创建两个临时文件 - imageoutput 包含不受支持的图像,outputtemp 包含可被 openpyxl 修改而不会损坏的工作表。然后最后将它们缝合在一起。

某些部分可能效率低下;请编辑或评论改进!

import os
import shutil
import win32com.client

from openpyxl import load_workbook

name = 'spreadsheet.xlsx'
outputfile = 'output.xlsx'
outputtemp = 'outputtemp.xlsx'

shutil.copyfile(name, 'output.xlsx')
wb = load_workbook('output.xlsx')
ws = wb['TWC']

# TWC doesn't have images. Anything ending with 'Results' has unsupported images etc

# Create new file with only openpyxl-unsupported worksheets
imageworksheets = [ws if ws.title.endswith('Results') else '' for ws in wb.worksheets]
if [ws for ws in wb if ws.title != 'TWC']:
    imageoutput = 'output2.xlsx'
    imagefilewritten = False
    while not imagefilewritten:
        try:
            shutil.copy(name, imageoutput)
        except PermissionError as error:
            # Catch an exception here - I usually have a GUI function
            pass
        else:
            imagefilewritten = True

    excel = win32com.client.Dispatch('Excel.Application')
    excel.Visible = False
    imagewb = excel.Workbooks.Open(os.path.join(os.getcwd(), imageoutput))
    excel.DisplayAlerts = False

    for i, ws in enumerate(imageworksheets[::-1]): # Go backwards to avoid reindexing
        if not ws:
            wsindex = len(imageworksheets) - i
            imagewb.Worksheets(wsindex).Delete()

    imagefileupdated = False
    while not imagefileupdated:
        try:
            imagewb.Save()
            imagewb.Close(SaveChanges = True)
            print('Temp image workbook saved.')
        except PermissionError as error:
            # Catch exception
            pass
        else:
            imagefileupdated = True

# Remove the unsupported worksheets in openpyxl
for ws in wb.worksheets:
    if ws in imageworksheets:
        wb.remove(ws)
wb.save(outputtemp)
print('Temp output workbook saved.')

''' Do your desired openpyxl manipulations on the remaining supported worksheet '''

# Merge the outputtemp and imageoutput into outputfile
wb1 = excel.Workbooks.Open(os.path.join(os.getcwd(), outputtemp))
wb2 = excel.Workbooks.Open(os.path.join(os.getcwd(), imageoutput))

for ws in wb1.Sheets:
    ws.Copy(wb2.Sheets(1))

wb2.SaveAs(os.path.join(os.getcwd(), outputfile))
wb1.Close(SaveChanges = True)
wb2.Close(SaveChanges = True)
print(f'Output workbook saved as {outputfile}.')

excel.Visible = True
excel.DisplayAlerts = True
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Openpyxl 在保存时损坏 xlsx。即使没有做出任何改变 的相关文章

  • Python for 循环仅返回字典的最后一个值

    我正在尝试在 python 中创建一个带有 xyz 坐标的 json 转储 但是我用来遍历不同组的 for 循环仅返回最后一个组 self group strings CHIN L EYE BROW R EYE BROW L EYE R E
  • 现在与出生日期之间的年、月、日、分钟差异

    import datetime birthday datetime datetime 1996 8 15 differnce datetime datetime now birthday This returns a timedelta o
  • 使用 Boto3 进行 IAM 身份验证的 SQLAlchemy 可刷新凭证

    我使用 Boto3 生成的身份验证令牌通过 Sqlalchemy 连接到 Amazon RDS self client boto3 client rds region name eu central 1 self token self cl
  • 如何让VLOOKUP在VBA中选择到最低行?

    希望自动在单元格中插入 VLOOKUP 公式 录制宏时 我指示它使用相同的公式填充下面的列 效果很好 但是 当 VLOOKUP 搜索的表发生变化 更多或更少的行 时 就会出现问题 在记录时 VLOOKUP 下降到表中的最后一行 273 但是
  • VBA 中的多线程

    这里有人知道如何让VBA运行多线程吗 我正在使用 Excel 无法用 VBA 本地完成 VBA 构建在单线程单元中 获得多个线程的唯一方法是使用 VBA 之外的其他具有 COM 接口的东西构建 DLL 并从 VBA 调用它 信息 OLE 线
  • 如何找到特定程序的安装目录?

    我已经成功地编写了一些用于工作的 VBA 宏 这些宏基本上创建了一个数据文件 将其提供给一个程序并对该程序的输出进行后处理 我的问题是程序安装路径是硬编码在宏中的 并且安装在我同事的计算机上可能会有所不同 我首先想到的是 我可以从每个人那里
  • 如何在Python中获取声音级别?

    对于我正在进行的项目 我需要获取麦克风的实时分贝级别 我见过阴谋家 Print out realtime audio volume as ascii bars import sounddevice as sd import numpy as
  • 如何只获取父类对象的属性

    我有两节课 class Parent object def init self id name self id id self name name self parent vars id name make a copy def print
  • VBA 完成 Internet 表单

    我正在寻找将 Excel 中的值放入网页的代码 Sub FillInternetForm Dim IE As Object Set IE CreateObject InternetExplorer Application IE naviga
  • Excel 数字缩写格式

    这是我想要完成的任务 Value Display 1 1 11 11 111 111 1111 1 11k 11111 11 11k 111111 111 11k 1111111 1 11M 11111111 11 11M 11111111
  • 输入新行并复制上面单元格中的公式

    我正在尝试创建一个 Excel 宏来执行以下操作 在文档末尾输入新行 复制上面单元格中的公式 到目前为止我有这个 Sub New Delta Go to last cell Range A4 Select Selection End xlD
  • 在Excel中,我可以使用超链接来运行vba宏吗?

    我有一个包含多行数据的电子表格 我希望能够单击一个单元格 该单元格将使用该行中的数据运行宏 由于行数总是在变化 我认为每行的超链接可能是最好的方法 ROW MeterID Lat Long ReadX ReadY ReadZ CoeffA
  • 两个日期之间的小时数在 Excel 中不起作用

    根据要求 我提供了一张简化的屏幕截图来说明该问题 如您所见 我减去了两个日期并将其格式化为 h mm ss 为什么这不能提供两个日期之间经过的总小时数 有一个更好的方法吗 下面有一个很好的答案 但我试图弄清楚为什么按照此屏幕截图中所示的方式
  • 表达式中的 Python 'in' 关键字与 for 循环中的比较 [重复]

    这个问题在这里已经有答案了 我明白什么是in运算符在此代码中执行的操作 some list 1 2 3 4 5 print 2 in some list 我也明白i将采用此代码中列表的每个值 for i in 1 2 3 4 5 print
  • C# 无法将欧元符号打印到文件中(使用 Excel 打开时)

    我在使用 Web api 控制器的 get 方法时遇到问题 此方法返回一个 HttpResponseMessage 对象 该对象具有带有 csv 文件的 HttpContent 其中包含欧元符号 当该方法返回文件时 不会打印欧元符号 该方法
  • 使用 ADODB 连接从关闭的工作簿中检索数据。某些数据被跳过?

    我目前正在编写一些代码 可以通过 ADODB 连接访问单独的工作簿 由于速度的原因 我选择了这种方法而不是其他方法 下面是我的代码 Sub GetWorksheetData strSourceFile As String strSQL As
  • shap.TreeExplainer 和 shap.Explainer 条形图之间的区别

    对于下面给出的代码 我得到了不同的条形图shap values 在此示例中 我的数据集为 1000train样本有 9 个类别和 500 个test样品 然后 我使用随机森林作为分类器并生成模型 当我开始生成shap条形图在这两种情况下得到
  • 在 Excel 中生成随机 -1 和 +1 值

    The Rand 函数会生成一个 0 到 1 之间的实数 这Randbetween 1 1 将生成 1 0 或 1 我想要的只是 1或1 那么 1 到 1 之间的实数呢 Easy IF RAND lt 0 5 1 1 要获得实数 请使用 R
  • ipython/ pylab/ matplotlib安装和初始化错误

    我在 OS X El Captain 上安装了 matplotlib anaconda ipython 然而 即使在尝试以所有可能的方式设置环境变量之后 我仍无法启动 ipython shell pylab 版本 这是错误 ImportEr
  • neo4j - python 驱动程序,服务不可用

    我对 neo4j 非常陌生 我正在尝试建立从 python3 6 到 neo4j 的连接 我已经安装了驱动程序 并且刚刚开始执行第一步 导入请求 导入操作系统 导入时间 导入urllib 从 neo4j v1 导入 GraphDatabas

随机推荐