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

Parse large split XML file(s) with Python

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

基本上我需要为 'record' 元素解析这些文件,然后从每个元素中提取 time 子元素

由于这些日志文件在随机位置拆分并且不一定有根目录,因此我使用 Python3 和 lxml 的 etree.iterparsehtml=True。这是处理由于分割文件导致的根节点缺失。但是,我不确定如何处理最终在一个文件的末尾和另一个文件的开头之间拆分的记录。

这里是拆分文件的一小部分示例。

文件:测试。001.txt

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

文件:测试。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]

那么有没有一种简单的方法来捕获在文件之间拆分的第 3 条记录?我真的不想提前合并文件,因为它们可能很多而且非常大。此外,除了这个 Using Python Iterparse For Large XML Files 之外的任何其他速度/内存管理技巧......我会弄清楚接下来该怎么做。添加 timeStamps 似乎可能有问题,因为它们可能有很多......但我无法真正分配,因为我不知道提前有多少。

当然可以。创建一个 行为 类似于文件的 class(通过提供 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

此 class 维护一个打开文件列表。如果 "topmost" 文件无法满足读取请求,则关闭该文件并尝试从后续文件读取。这一直持续到我们读取了足够的字节或者我们 运行 文件不足。

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

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