用win32com在python中编写数组到excel

时间:2014-01-31 11:26:03

标签: python excel win32com

我正在制作一个解析数据文件的python。然后将解析的数据发送到excel文件。 数据可能相当庞大。我正在看10到20列,但行数可以超过100.000。

使用win32com将此数据量写入excel需要相当长的时间。我的第一步是在excel文件中迭代遍历单元格,这非常耗时。经过一番挖掘后,我发现如何通过一次调用来编写一行,从而大大减少了所需的时间。

但是,当我需要向Excel发送100.000行数据时,仍然需要花费很多时间。我很确定通过一次调用发送完整的数组,我可以进一步提高速度。但是到目前为止我无法做到这一点。

请参阅下面的代码,该代码演示了此问题。代码显示了时间上的差异。但是,第三步,通过单个调用向一个范围发送完整数组不会导致excel中的正确数据。我做错了什么?

import win32com.client
import time

#create data array
row = range(0,10)
i = 0
data_array = []
while i < 1000:
    data_array.append(row)
    i += 1

#write the array to an excel file
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True
excel.ScreenUpdating = False
book = excel.Workbooks.Add()
sh1 = book.Worksheets(1)
sh2 = book.Worksheets(2)
sh3 = book.Worksheets(3)

#double loop, writing individual cells
print "Writing with double loop to inidividual cells."
start = time.time()
row = 0
for line in data_array:
    row += 1
    col = 0
    for field in line:
        col += 1
        sh1.Cells(row, col).Value = field
print "Processing time: " + str(time.time() - start) + " seconds."

#single loop, writing a row to a range
print "Writing with double loop to inidividual cells."
start = time.time()
row = 0
for line in data_array:
    row += 1
    sh2.Range(sh2.Cells(row,1), sh2.Cells(row, len(line))).Value = line
print "Processing time: " + str(time.time() - start) + " seconds."

#no loop, write array to range
print "Writing with double loop to inidividual cells."
start = time.time()
try:
    sh3.Range(sh3.Cells(row,1), sh3.Cells(len(data_array), len(data_array[0]))).Value = data_array
    print "Processing time: " + str(time.time() - start) + " seconds."
except:
    print "Failed to write array to excel file."

excel.ScreenUpdating = True
sheet = None
book = None
excel.Quit()
excel = None

2 个答案:

答案 0 :(得分:4)

我一直在研究这个问题。并且已经得出了一些有趣的结论。

确实有多种解决方案可以将数据从python写入excel。我最终专注于三个模块。

<强> win32com.client

工作缓慢。但是文档可以在excel中打开。因此,最终结果可供excel中的用户开始使用。不适合大量数据。

在我的计算机(核心i5)app上编写10,000行10列。 70秒。

import win32com.client
import time

#create data array
row = range(0,10)
i = 0
data_array = []
while i < 10000:
    data_array.append(row)
    i += 1

#write the array to an excel file
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True
excel.ScreenUpdating = False
book = excel.Workbooks.Add()
sheet = book.Worksheets(1)

#single loop, writing a row to a range
print "Writing using win32com.client"
start = time.time()
row = 0
for line in data_array:
    row += 1
    sheet.Range(sheet.Cells(row,1), sheet.Cells(row, len(line))).Value = line
print "Processing time: " + str(time.time() - start) + " seconds."

print "Completed: " + str(time.time() - start) + " seconds."
excel.ScreenUpdating = True
sheet = None
book = None
excel.Quit()
excel = None

<强> openpyxl

有点快,但仍然不是很好。此模块在将数据传输到Excel内存对象时速度很慢,但保存速度非常快。它在22.3秒内创建10,000行10列,并在另外0.5秒内保存文件。 当我用100,000行和10列测试时。数据在228.3秒内创建,保存文件在另外2.9秒内完成。相当慢,但文件保存速度很快。因此openpyxl可能适合对现有数据进行更改(格式化),尽管我还没有对此进行测试。 另一个优点是使用win32com.client进行使用openpyxl编码更容易。

import openpyxl
import sys
import time

#create data array
row = range(0,10)
i = 0
data_array = []
while i < 10000:
    data_array.append(row)
    i += 1

#create an excel workbook and sheet object
book = openpyxl.Workbook(optimized_write = True)

#single loop, writing rows
start = time.time()
print "Writing with single loop using openpyxl"
sheet = book.create_sheet()
for line in data_array:
    sheet.append(line)
print "Processing time: " + str(time.time() - start) + " seconds."

#close and save the file.
book.save('openpyxl.xlsx')
print "Total time: " + str(time.time() - start) + " seconds."

我正面临着openpyxl的另一个问题。在我的真实工具中,openpyxl在保存大量数据(> 10,000行)方面存在问题。我还没想到,也许我不想再深入了解它。

<强> PyExcelerate

这首先是快速的。它在0.17秒内创建了10,000行和10列。但是保存文件需要2.2秒。到目前为止三者中最快的选择。 当我尝试使用此模块保存100,000行和10列时,excel数据仅在1.8秒内创建。但是现在保存文件需要21.7秒。 因此,这个模块非常快,但写文件会受到惩罚。整体而言仍然是最快的。 PyExcelerate的另一个优点是编码非常简单,再次像openpyxl一样容易。

import pyexcelerate
import sys
import time

#create data array
row = range(0,10)
i = 0
data_array = []
while i < 10000:
    data_array.append(row)
    i += 1

print sys.version

#create an excel workbook and sheet object
book = pyexcelerate.Workbook()

#single loop, writing rows
start = time.time()
print "Writing with single loop using PyExcelerate"
book.new_sheet("data", data = data_array)

print "Processing time: " + str(time.time() - start) + " seconds."

#close and save the file.
book.save('pyexcelerate.xlsx')
print "Total time: " + str(time.time() - start) + " seconds."

所以我的结论是PyExcelerate是迄今为止最快的。 win32com.client的优点是创建的excel文件可以在excel中打开,以使创建的数据可供用户开始使用它。在创建样式后,Openpyxl可能很有趣。但是,我还没有测试过这个。 因此,在一个应用程序中组合win32com.client,openpyxl和PyExcelerate可能是有益的。

答案 1 :(得分:3)

使用COM从excel文件中读取文件极度浪费时间。这就像用坦克杀死苍蝇一样。考虑到win32com使用windows API执行复杂的调用,与excel通信,检索数据并将其发送回python。当信息作为文件存在时,为什么这样做?

有些库可以直接解析excel文件,你可以想象它们的速度可以快100倍,因为对于win API没有过于复杂的调用。

我使用openpyxl成功地做了很多工作,但是还有其他库可以做得更好甚至更好。

只是大数据的一个例子(使用生成器而不是将所有内容加载到内存中):

from openpyxl import load_workbook
wb = load_workbook(filename='large_file.xlsx', use_iterators=True)
ws = wb.get_sheet_by_name(name='big_data') # ws is now an IterableWorksheet

for row in ws.iter_rows(): # it brings a new method: iter_rows()
     for cell in row:
         print cell.internal_value

可以使用等效方法写入单元格。你甚至可以格式化它们,虽然它不是(或曾经)非常完整。

修改

如何将大量信息写入xlsx文件的示例:

from openpyxl import Workbook
from openpyxl.cell import get_column_letter

wb = Workbook()
dest_filename = r'empty_book.xlsx'
ws = wb.active
ws.title = "range names"

for col_idx in xrange(1, 40):
    col = get_column_letter(col_idx)
    for row in xrange(1, 600):
        ws.cell('%s%s'%(col, row)).value = '%s%s' % (col, row)

ws = wb.create_sheet()
ws.title = 'Pi'
ws['F5'] = 3.14
wb.save(filename=dest_filename)