使用Python解析大型拆分XML文件

时间:2015-07-31 01:31:42

标签: python lxml

我有一个非常大的XML日志文件,可以自动拆分固定大小(~200MB)。可以有很多部分(通常少于10个)。当它分裂时,它不会在记录结束时甚至在当前行的末尾整齐地进行。它只要达到目标大小就会分裂。

基本上我需要解析这些文件以便记录'然后,元素从其他事物中拉出time孩子

由于这些日志文件在随机位置拆分而且不一定有根,我使用的是Python3和lxml的etree.iterparse html=True。这是因为拆分文件导致缺少根节点。但是,我不知道如何处理最终在一个文件的结尾和另一个文件的开头之间拆分的记录。

以下是分割文件可能的样子的小样本。

文件:test.001.txt

<records>
<record>
    <data>5</data>
    <time>1</time>
</record>
<record>
    <data>5</data>
    <time>2</time>
</record>
<record>
    <data>5</data>
    <ti

文件:test.002.txt

me>3</time>
</record>
<record>
    <data>6</data>
    <time>4</time>
</record>
<record>
    <data>6</data>
    <time>5</time>
</record>
</records>

以下是我所尝试过的,我知道它无法正常工作:

from lxml import etree
xmlFiles      = []
xmlFiles.append('test.001.txt')
xmlFiles.append('test.002.txt')
timeStamps = []
for xmlF in xmlFiles:
    for event, elem in etree.iterparse(xmlF, events=("end",), tag='record',html=True):
        tElem = elem.find('time')
        if tElem is not None:
            timeStamps.append(int(tElem.text))

输出:

In[20] : timeStamps
Out[20]: [1, 2, 4, 5]

那么有一种简单的方法来捕获在文件之间分割的第三条记录吗?我并不是真的想提前合并文件,因为它们可能很多并且它们非常大。此外,除此Using Python Iterparse For Large XML Files之外的任何其他速度/内存管理提示......我将了解如何执行此操作。 timeStamps的附加似乎可能有问题,因为可能有很多......但我无法真正分配,因为我不知道有多少提前。

1 个答案:

答案 0 :(得分:4)

不确定。创建一个行为类的类(通过提供read方法),但实际上从多个文件中获取输入,同时从调用者隐藏此事实。类似的东西:

class Reader (object):
    def __init__(self):
        self.files = []

    def add(self, src):
        self.files.append(src)

    def read(self, nbytes=0):
        if not len(self.files):
            return bytes()

        data = bytes()
        while True:
            data = data + self.files[0].read(nbytes - len(data))
            if len(data) == nbytes:
                break

            self.files[0].close()
            self.files.pop(0)
            if not len(self.files):
                break

        return data

此类维护打开文件的列表。如果“最顶层”文件无法满足读取请求,则关闭该文件并尝试从后续文件读取。这一直持续到我们读取足够的字节或文件用完为止。

鉴于上述情况,如果我们这样做:

r = Reader()
for path in ['file1.txt', 'file2.txt']:
    r.add(open(path, 'rb'))

for event, elem in etree.iterparse(r):
    print event, elem.tag

我们得到(使用你的样本输入):

end data
end time
end record
end data
end time
end record
end data
end time
end record
end data
end time
end record
end data
end time
end record
end records