代码之家  ›  专栏  ›  技术社区  ›  S.Lott

如何围绕SAX解析器包装适当的生成器函数

  •  -4
  • S.Lott  · 技术社区  · 14 年前

    我有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解析器中创建一个临时文件,然后通过生成器生成这些对象更简单?

    相关: Lazy SAX XML parser with stop/resume .

    2 回复  |  直到 6 年前
        1
  •  5
  •   Andre Holzner    6 年前

    “我有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列)加载到XLRD对象模型中:

    运行windows xp和python 2.7的时间大约是4分钟。增量内存使用在大约300MB的内存上达到最大,其中大部分是输出,而不是元素树。

        2
  •  1
  •   adw    14 年前

    好像你可以用 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所不支持的。