我有一个打开xlsm文件和xlsx文件的脚本。它使用来自xlsx的数据修改xlsm,然后保存xlsm文件。在脚本运行后打开该xlsm文件时,出现如图所示的错误。
我正在使用的代码是:
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")
Joost在这个问题中,我遇到了类似的问题,并且从该解决方案中提取了大部分可回收的代码:How to save XLSM file with Macro, using openpyxl
显然,在打开和保存时,openpyxl不会读取或保留xslm的所有魔术宏部分。由于文件为zip格式,因此解决方案:
我获取了示例代码,将其转换为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')