在Python 2.7中高效读取800 GB XML文件

Mik*_*e S 20 python xml io file python-2.7

我正在读取python 2.7中的800 GB xml文件,并使用etree迭代解析器解析它.

目前,我只使用open('foo.txt')没有缓冲参数.我有点困惑这是我应该采取的方法,还是我应该使用缓冲参数或使用io中的东西,如io.BufferedReader或io.open或io.TextIOBase.

正确方向的一点将非常感激.

Mar*_*ers 15

默认情况下,标准open()函数已返回缓冲文件(如果在您的平台上可用).对于通常完全缓冲的文件对象.

通常这里意味着Python将此保留给C stdlib实现; 它使用一个fopen()调用(wfopen()在Windows上支持UTF-16文件名),这意味着选择了一个文件的默认缓冲; 在Linux上我相信这将是8kb.对于像XML解析这样的纯读取操作,这种类型的缓冲正是您想要的.

通过iterparse以16384字节(16kb)的块读取文件来完成XML解析.

如果要控制buffersize,请使用buffering关键字参数:

open('foo.xml', buffering=(2<<16) + 8)  # buffer enough for 8 full parser reads
Run Code Online (Sandbox Code Playgroud)

这将覆盖默认的缓冲区大小(我希望它与文件块大小或其倍数相匹配).根据这篇文章,增加读缓冲区应该有所帮助,并且使用至少4倍的预期读取块大小加上8个字节的大小将提高读取性能.在上面的例子中,我将它设置为ElementTree读取大小的8倍.

io.open()函数表示对象的新Python 3 I/O结构,其中I/O已拆分为新的类类型层次结构,以提供更大的灵活性.价格更加间接,数据必须通过更多层,而Python C代码本身更有效,而不是将其留给操作系统.

可以尝试看看是否io.open('foo.xml', 'rb', buffering=2<<16)会有更好的表现.在rb模式下打开将为您提供一个io.BufferedReader实例.

希望使用io.TextIOWrapper; 底层的expat解析器需要原始数据,因为它将解码您的XML文件编码本身.它只会增加额外的开销; 如果你打开r(textmode)而得到这种类型.

使用io.open()可能会给你更多的灵活性和更丰富的API,但底层的C文件对象是使用open()而不是打开的fopen(),并且所有缓冲都由Python io.BufferedIOBase实现处理.

我认为你的问题将是处理这个野兽,而不是文件读取.在读取800GB文件时,磁盘缓存无论如何都会被拍摄.

  • @poke:这就是`iterparse()`是*for*.它为您提供了使用ElementTree API进行事件驱动的解析,因此您可以根据需要再次释放元素. (3认同)