我有35.5Mb .XLSM文件。当实际可用内容被扩展时,它会在很长很长的运行时间之后淹没DOM解析器,例如元素树耗尽内存。
但是,在使用SAX解析器时,ContentHandler
似乎被限制为在临时文件中累积行。这有点令人恼火,因为解析器和主应用程序可以具有简单的协同例程关系,其中SAX解析的每一行都可以产生给应用程序。
看起来不太可能。
def gen_rows_from_xlsx( someFile ):
myHandler= HandlerForXLSX()
p= xml.sax.makeParser()
p.setContentHandler( myHandler, some_kind_of_buffer )
for row in some_kind_of_buffer.rows():
p.parse() # Just enough to get to the ContentHandler's "buffer.put()"
yield row
HandlerForXLSX
会定期调用some_kind_of_buffer.put( row )
将一行放入缓冲区。这一行应该通过some_kind_of_buffer.rows()
产生。
SAX解析器与gen_rows_from_xslx()
之间的简单协程关系是理想的。
我是否忽略了一些生成器功能魔法,它允许我将SAX打包为某种协程?
是创建SAX解析线程并使用Queue
来获取解析器构建的行的唯一替代方法吗?
或者更容易咬住子弹并在SAX解析器中创建一个临时文件,然后通过生成器生成这些对象?
答案 0 :(得分:5)
“”“我有35.5Mb .XLSM文件。当实际可用内容被扩展时,它会在很长很长的运行时间之后淹没像元素树耗尽内存的DOM解析器。”“”
我不明白这一点。你应该使用的东西:
import xml.etree.cElementTree as ET
ET.iterparse(sourcefile) # sourcefile being a cStringIO.StringIO instance holding your worksheet XML document
element.clear() # leave only scorched earth behind you
This article显示了如何使用iterparse
和clear
。
示例:将XLSX(100Mb,大部分是两个工作表,每个工作表大约有16K行,大约200个col)加载到xlrd对象模型中:
经过约4分钟的时间[打败旧笔记本电脑[2 GHz单核]运行Windows XP和Python 2.7]。增量内存使用量最大约为300Mb内存,其中大部分是输出,而不是元素树。
答案 1 :(得分:1)
好像你可以使用IncrementalParser
界面吗?类似的东西:
def gen_rows_from_xlsx(someFile):
buf = collections.deque()
myHandler = HandlerForXLSX(buf)
p = xml.sax.make_parser()
p.setContentHandler(myHandler)
with open(someFile) as f:
while True:
d = f.read(BLOCKSIZE)
if not d: break
p.feed(d)
while buf: yield buf.popleft()
p.close()
要使用parse
执行此操作,您必须在多个堆栈帧中yield
,这是Python根本不支持的内容。