使用 win32com 打开包含公式的 Excel 文件,添加一些延迟,并保存为 CSV
Use win32com to Open Excel file with formulas, add some delay, & save as CSV
我有一个 Excel 文件,里面有一堆公式。正确加载公式需要时间(~1-2 分钟),因此我试图在打开文件和保存加载文件之间添加一些延迟。完成此操作后,我希望将完全加载的 Excel 文件的副本另存为具有不同名称的新 CSV,以便我同时拥有完全加载的 Excel 文件和新的 CSV 文件.
明确地说,我正在尝试按此顺序执行以下任务:
- 打开 Excel 文件
- 添加一些延迟(约 1-2 分钟)
- 保存完全加载的 Excel 文件
- 将完全加载的 Excel 文件的副本另存为具有不同名称的 CSV
我已经成功完成了如下所示的第 1 步和第 3 步,但在执行第 2 步和第 4 步时遇到了问题。我注意到第 2 步非常重要,因为我现在编写代码的方式并不为公式加载留出足够的时间,从而导致文件加载不完整。
执行第 2 步和第 4 步的最佳方法是什么,即添加延迟,然后将整个文件另存为 CSV?
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
#opens file denoted by PATH
workbook = excel.Workbooks.Open(PATH)
#saves file
workbook.Save()
#closes and quits Excel
workbook.Close()
excel.Quit()
请注意此代码基于 this post。
您可以开始 Excel 计算,然后让您的 Python 代码等待:
import time
#...
workbook = excel.Workbooks.Open(PATH)
excel.CalculateFull() #If Calculation is set to Manual
#Wait 10 seconds
time.sleep(10)
workbook.Save()
#...
当然,你不知道10秒是太长还是太短。
更精确的方法是开始计算,然后等待 Excel 告诉您它已完成。 Excel Application 对象在完成计算树时发出 AfterCalculation
事件信号。您可以设置 Python 代码以等待此事件发出信号后再继续。
完整代码:
import win32com.client as wc
import pythoncom #From package pywin32
import win32api
import win32con
from os.path import join
#Class to handle the SyncObject events from Outlook
class CalcHandler(object):
def OnAfterCalculate(self):
#Calculation has finished so send WM_QUIT to message loop
win32api.PostThreadMessage(win32api.GetCurrentThreadId(), win32con.WM_QUIT, 0, 0)
print('... calculation complete')
#Get the application Dispatch interface
xl = wc.gencache.EnsureDispatch('Excel.Application')
path = 'path_to_directory'
#opens a file
workbook = xl.Workbooks.Open(join(path,'test.xlsx'))
if workbook is not None:
#Create an event handler
wc.WithEvents(xl,CalcHandler)
print('Starting calculation ...')
#Force a calcuation
xl.CalculateFull()
#This will block until a WM_QUIT message is sent to the message queue
pythoncom.PumpMessages()
#saves file as a CSV
xl.DisplayAlerts=False
workbook.SaveAs(join(path,'test.csv'),wc.constants.xlCSV)
#closes and quits Excel
workbook.Close()
if xl.Workbooks.Count == 0:
xl.Quit()
xl=None
我有一个 Excel 文件,里面有一堆公式。正确加载公式需要时间(~1-2 分钟),因此我试图在打开文件和保存加载文件之间添加一些延迟。完成此操作后,我希望将完全加载的 Excel 文件的副本另存为具有不同名称的新 CSV,以便我同时拥有完全加载的 Excel 文件和新的 CSV 文件.
明确地说,我正在尝试按此顺序执行以下任务:
- 打开 Excel 文件
- 添加一些延迟(约 1-2 分钟)
- 保存完全加载的 Excel 文件
- 将完全加载的 Excel 文件的副本另存为具有不同名称的 CSV
我已经成功完成了如下所示的第 1 步和第 3 步,但在执行第 2 步和第 4 步时遇到了问题。我注意到第 2 步非常重要,因为我现在编写代码的方式并不为公式加载留出足够的时间,从而导致文件加载不完整。
执行第 2 步和第 4 步的最佳方法是什么,即添加延迟,然后将整个文件另存为 CSV?
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
#opens file denoted by PATH
workbook = excel.Workbooks.Open(PATH)
#saves file
workbook.Save()
#closes and quits Excel
workbook.Close()
excel.Quit()
请注意此代码基于 this post。
您可以开始 Excel 计算,然后让您的 Python 代码等待:
import time
#...
workbook = excel.Workbooks.Open(PATH)
excel.CalculateFull() #If Calculation is set to Manual
#Wait 10 seconds
time.sleep(10)
workbook.Save()
#...
当然,你不知道10秒是太长还是太短。
更精确的方法是开始计算,然后等待 Excel 告诉您它已完成。 Excel Application 对象在完成计算树时发出 AfterCalculation
事件信号。您可以设置 Python 代码以等待此事件发出信号后再继续。
完整代码:
import win32com.client as wc
import pythoncom #From package pywin32
import win32api
import win32con
from os.path import join
#Class to handle the SyncObject events from Outlook
class CalcHandler(object):
def OnAfterCalculate(self):
#Calculation has finished so send WM_QUIT to message loop
win32api.PostThreadMessage(win32api.GetCurrentThreadId(), win32con.WM_QUIT, 0, 0)
print('... calculation complete')
#Get the application Dispatch interface
xl = wc.gencache.EnsureDispatch('Excel.Application')
path = 'path_to_directory'
#opens a file
workbook = xl.Workbooks.Open(join(path,'test.xlsx'))
if workbook is not None:
#Create an event handler
wc.WithEvents(xl,CalcHandler)
print('Starting calculation ...')
#Force a calcuation
xl.CalculateFull()
#This will block until a WM_QUIT message is sent to the message queue
pythoncom.PumpMessages()
#saves file as a CSV
xl.DisplayAlerts=False
workbook.SaveAs(join(path,'test.csv'),wc.constants.xlCSV)
#closes and quits Excel
workbook.Close()
if xl.Workbooks.Count == 0:
xl.Quit()
xl=None