我有一个由连接的XML文件组成的大型文本文件(我将每个文件称为'XML子文件')。
我知道当我来到字符串
时,每个新的XML部分都会启动<?xml version = "1.0"?>
目标是解析每个XML子文件,但作为第一步,我需要
我的想法是将文本文件拆分为单独的XML文件,然后我可以解析。 (其他想法?)
如何“循环”文本文件并将文件拆分?我无法读取整个文件,因为它太大,我无法遍历这些行(因为文件在技术上是一行,文件中没有换行符。)
知道如何在Python 3中解决这个问题吗?
PS:看起来这是一个类似的问题,但链接已经死了:
答案 0 :(得分:0)
假设输入文件相当大并且您可能不想将其完全加载到内存中,那么将其传输是有意义的。
Optimal是生成器,它会在某些点将文件的传入流分解为块,即当一条线等于你的“分裂”线时。
这可以概括为可以将任何可迭代分组的函数。 itertools.groupby有助于完成任务,我们需要做的就是当我们点击“split here”值时增加一个索引,并使用该索引作为组密钥:
from itertools import groupby
def split_chunks(values, split_val):
'''splits a list of values into chunks at a certain value'''
index = 0
def chunk_index(val):
nonlocal index
if val == split_val:
index += 1
return index
return groupby(values, chunk_index)
测试 - 让我们将数字列表拆分为0
:
for i, numbers in split_chunks([0,1,2,3,0,4,5,6,0,7,8,9], 0):
print(list(numbers))
打印
[0, 1, 2, 3] [0, 4, 5, 6] [0, 7, 8 ,9]
出现空行,因为输入中的第一个0
之前没有任何内容。拆分字符串'abcabc'.split('a')
时会发生完全相同的事情。
因此,使用“大文本文件中的行”代替“数字”很简单:
import xml.etree.ElementTree as ET
with open('large_container_file', 'r', encoding='utf8') as container_file:
for doc_num, doc in split_chunks(container_file, '<?xml version="1.0"?>'):
print(f'processing sub-document #{doc_num}')
tree = ET.fromstringlist(doc)
确保使用正确的编码打开容器文件。
由于生成器仅在您推进迭代时才起作用,因此在处理当前large_container_file
时读取tree
会停止,因此内存使用量应该相当低,与输入文件大小无关。
doc
在这种情况下是一个生成器,这很好,因为它非常节省内存。但与列表相反,您无法轻易找出它是否为空,如果'<?xml version="1.0"?>'
是文档中的第一行,则会出现这种情况。
ET.fromstringlist()
对生成器很满意,但是当它发现生成器为空时它会抛出。但是,当XML中存在错误时它也会抛出,所以我要做的是添加try
:
try:
tree = ET.fromstringlist(doc)
except:
pass
或者,您可以预先致电list()
,然后检查是否有任何行:
lines = list(doc)
if lines:
tree = ET.fromstringlist(lines)