如何在Python中生成超大XML文件?
有没有人知道在Python中生成非常大的XML文件(比如100到500兆字节)有什么节省内存的方法?
我一直在用lxml,但是内存使用量太高了。
4 个回答
生成这么大的XML文件,最靠谱的方法就是一行一行地生成。这就意味着在运行一个状态机的同时进行打印,而且需要大量的测试。
显然,你需要避免在内存中构建整个树(无论是DOM树、etree还是其他的)。不过,最好的方法取决于你的数据来源,以及你输出的结构有多复杂和相互关联。
如果数据量大是因为有成千上万的相对独立的项目,那么你可以先生成一个外层的包装,然后为每个项目构建树,最后把每个部分序列化输出。
如果这些部分之间的关系不那么独立,那么你就需要做一些额外的管理,比如可能需要管理一个生成的ID和引用ID的数据库。
我会把这个过程分成两到三个部分:一个是SAX事件生成器,一个是处理SAX事件的输出序列化器,另外,如果处理一些独立的部分作为对象或树更方便的话,可以再加一个构建这些对象的部分,然后把它们转化为SAX事件供序列化器使用。
也许你可以直接管理文本输出,而不是处理SAX事件,这要看具体情况有多复杂。
这也是一个很好的机会使用Python生成器,这样可以在不需要在内存中构建大型结构的情况下流式输出数据。
也许你可以考虑使用模板引擎,而不是自己手动生成或构建XML文件?
比如说,Genshi就是一个基于XML的模板引擎,它支持流式输出。下面是一个非常简单的例子:
from genshi.template import MarkupTemplate
tpl_xml = '''
<doc xmlns:py="http://genshi.edgewall.org/">
<p py:for="i in data">${i}</p>
</doc>
'''
tpl = MarkupTemplate(tpl_xml)
stream = tpl.generate(data=xrange(10000000))
with open('output.xml', 'w') as f:
stream.render(out=f)
虽然可能需要一些时间,但它的内存使用量保持得很低。
再来看一个使用Mako模板引擎的例子(虽然它不是“原生”的XML),但速度要快很多:
from mako.template import Template
from mako.runtime import Context
tpl_xml = '''
<doc>
% for i in data:
<p>${i}</p>
% endfor
</doc>
'''
tpl = Template(tpl_xml)
with open('output.xml', 'w') as f:
ctx = Context(f, data=xrange(10000000))
tpl.render_context(ctx)
最后这个例子在我的笔记本上运行了大约20秒,生成了一个(确实非常简单的)151 MB的XML文件,完全没有内存问题。(根据Windows任务管理器,它的内存使用量保持在大约10MB左右)
根据你的需求,这可能比使用SAX等方法生成XML更友好、更快速……可以查看这些引擎的文档,看看你能用它们做些什么(还有其他的引擎,我只是挑了这两个作为例子)