我正在 python 2.7 中读取一个 800 GB 的 xml 文件,并使用 etree 迭代解析器对其进行解析。
目前,我只是open('foo.txt')
在没有缓冲参数的情况下使用。我有点困惑这是我应该采用的方法,还是应该使用缓冲参数或使用来自 io 的东西,如 io.BufferedReader 或 io.open 或 io.TextIOBase。
一个正确方向的观点将不胜感激。
我正在 python 2.7 中读取一个 800 GB 的 xml 文件,并使用 etree 迭代解析器对其进行解析。
目前,我只是open('foo.txt')
在没有缓冲参数的情况下使用。我有点困惑这是我应该采用的方法,还是应该使用缓冲参数或使用来自 io 的东西,如 io.BufferedReader 或 io.open 或 io.TextIOBase。
一个正确方向的观点将不胜感激。
默认情况下,标准open()
函数已经返回一个缓冲文件(如果在您的平台上可用)。对于通常完全缓冲的文件对象。
通常这里意味着 Python 将其留给 C stdlib 实现;它使用fopen()
调用(wfopen()
在 Windows 上支持 UTF-16 文件名),这意味着选择了文件的默认缓冲;在 Linux 上,我相信这将是 8kb。对于像 XML 解析这样的纯读取操作,这种类型的缓冲正是您想要的。
XML 解析由iterparse
16384 字节 (16kb) 的块读取文件。
如果要控制缓冲区大小,请使用buffering
关键字参数:
open('foo.xml', buffering=(2<<16) + 8) # buffer enough for 8 full parser reads
这将覆盖默认缓冲区大小(我希望与文件块大小或其倍数匹配)。根据这篇文章,增加读取缓冲区应该会有所帮助,并且使用至少 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) 中打开,你会得到这种类型。
Usingio.open()
可能会给你更多的灵活性和更丰富的 API,但是底层的 C 文件对象是使用open()
而不是打开的fopen()
,并且所有的缓冲都由 Pythonio.BufferedIOBase
实现处理。
我认为你的问题将是处理这个野兽,而不是文件读取。无论如何,在读取 800GB 文件时,磁盘缓存几乎都会被拍摄。
你尝试过惰性函数吗?:在 Python 中读取大文件的惰性方法?
这似乎已经回答了你的问题。但是,我会考虑使用这种方法将您的数据写入数据库,mysql 是免费的:http : //dev.mysql.com/downloads/,NoSQL 也是免费的,并且可能更适合涉及写入 800gb 的操作数据或类似数量:http ://www.oracle.com/technetwork/database/nosqldb/downloads/default-495311.html
我还没有尝试过使用这种史诗般的 xml 文件,但上次我不得不处理大型(且相对简单的)xml 文件时,我使用了sax parser。
它基本上为您提供每个“事件”的回调,并留给您存储您需要的数据。您可以提供一个打开的文件,这样您就不必一次全部阅读。