【问题标题】:Python openpyxl saving xlsm file gets error when openingPython openpyxl保存xlsm文件打开时出错
【发布时间】:2017-01-05 13:32:08
【问题描述】:

我有一个脚本可以打开一个 xlsm 文件和一个 xlsx 文件。它使用来自 xlsx 的数据修改 xlsm,然后保存 xlsm 文件。当我在脚本运行后打开那个 xlsm 文件时,我得到了如图所示的错误。

该文件然后可以正常工作,但我收到如下所示的 XML 错误:

我使用的代码是:

import openpyxl
destwb = openpyxl.load_workbook(filename="C:\\627 Data\\winphy\\071-000-022-00 627 data.xlsm", read_only=False, keep_vba=True)

.....Code.....

destwb.save(filename="C:\\627 Data\\winphy\\071-000-022-00 627 data2.xlsm")

【问题讨论】:

  • 修复的摘要部分未关闭,“摘要”缺失
  • 很遗憾,Excel 文件错误不是很有帮助,没有该文件我们无法为您提供帮助。
  • 我不确定如何将文件附加到线程,但是一旦我打开文件并再次保存,错误就消失了。
  • @mickNeill 看来您将其保存为 xls。我不确定openpyxl中的save是否可以这样保存xlsm文件!

标签: python xml excel vba openpyxl


【解决方案1】:

我在这个问题中遇到了Joost 从这个解决方案中拼凑出的类似的大部分回收代码:How to save XLSM file with Macro, using openpyxl

显然,openpyxl 在打开和保存时不会读取或保存 xslm 的所有魔术宏部分。由于文件是zip格式,解决方法:

  • 将您的工作保存为 xlsx
  • 以 zip 格式打开原始 xlsm 并提取关键部分
  • 使用您保存的 xlsx 和上述关键部分中的数据创建一个新的 zip 文件
  • 将其重命名为 xlsm

我采用了示例代码,将其变成了 workbook.save() 的可用替代品,修复了丢失的文件(可能是 Excel 与原始解决方案相比发生了变化),添加了 zip 压缩和创建备份文件。愿这能满足你的需要。

def saveXlsm(wb, xlsmname):
'''Some crazy workaround to fix what openpyxl cannot when recreating an xlsm file. 
   Use as replacement for workbook.save()
'''
import zipfile
from shutil import copyfile
from shutil import rmtree

# Unzip original and tmp into separate dirs
PAD = os.getcwd()
wb.save('tmp.xlsx')
with zipfile.ZipFile(xlsmname, 'r') as z:
    z.extractall('./xlsm/')
with zipfile.ZipFile('tmp.xlsx', 'r') as z:
    z.extractall('./xlsx/')
# copy pertinent left out macro parts into tmp
copyfile('./xlsm/[Content_Types].xml','./xlsx/[Content_Types].xml')
copyfile('./xlsm/xl/_rels/workbook.xml.rels','./xlsx/xl/_rels/workbook.xml.rels')
copyfile('./xlsm/xl/vbaProject.bin','./xlsx/xl/vbaProject.bin')
copyfile('./xlsm/xl/sharedStrings.xml','./xlsx/xl/sharedStrings.xml')
# create a new tmp zip to rebuild the xlsm
z = zipfile.ZipFile('tmp.zip', 'w', zipfile.ZIP_DEFLATED)
# put all the parts back into the new Frankenstein
os.chdir('./xlsx')
for root, dirs, files in os.walk('./'):
        for file in files:
            z.write(os.path.join(root, file))
z.close()
os.chdir(PAD)
# humanize Frankenstein
bakname = xlsmname + '.bak'
if os.access(bakname, os.W_OK):
    os.remove(bakname)
os.rename(xlsmname, bakname)
os.rename('tmp.zip', xlsmname)
#clean
rmtree('./xlsm/')
rmtree('./xlsx/')
os.remove('./tmp.xlsx')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多