You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何快速移除大文件中的多份XML声明?Python优化方案咨询

问题描述

我有一批本地存储的大文件,单个文件约含1100万行(450MB),文件内存在多份XML声明及指定DOCTYPE内容。目前我通过Python将文件视为.txt文件,逐行过滤掉这些内容后写入新文件,但单个文件处理耗时约20分钟,效率极低,寻求更高效的实现方案。

当前代码

month_file = "2015-01.nml.txt"

delete_lines = [
        '<?xml version="1.0" encoding="ISO-8859-1" ?>',
        '<?xml version="1.0" encoding="iso-8859-1" ?>',
        '<!DOCTYPE doc SYSTEM "djnml-1.0b.dtd">',    
    ] 
                   
with open(month_file, encoding="ISO-8859-1") as in_fh:
    while True:
        line = in_fh.readline()
        if not line: break

        if any(x in line for x in delete_lines):
            continue 
        else:
            out_fh = open('myfile_faster.xml', "a")
            out_fh.write(line)        
    out_fh.close()

低效原因分析

  1. 频繁打开/关闭输出文件:循环内每次写入都重新打开输出文件,文件IO是系统中最慢的操作之一,频繁的打开关闭会产生巨大性能开销,这是导致速度慢的核心原因。
  2. 逐行读取的方式不够高效:readline()循环的性能不如Python文件对象的原生迭代器。
  3. 字符串匹配效率低:any(x in line for x in delete_lines)每次遍历列表做子串匹配,若目标是整行匹配,用集合查找会更快。

优化方案

1. 核心优化:将输出文件放在循环外打开

这是最立竿见影的优化,避免频繁IO操作:

month_file = "2015-01.nml.txt"
output_file = 'myfile_faster.xml'

# 用集合存储待过滤行,查找速度远快于列表
delete_lines = {
        '<?xml version="1.0" encoding="ISO-8859-1" ?>',
        '<?xml version="1.0" encoding="iso-8859-1" ?>',
        '<!DOCTYPE doc SYSTEM "djnml-1.0b.dtd">',    
    } 

# 同时打开输入和输出文件,循环内仅做写入操作
with open(month_file, encoding="ISO-8859-1") as in_fh, open(output_file, 'w', encoding="ISO-8859-1") as out_fh:
    # 用文件迭代器遍历,比readline()更高效
    for line in in_fh:
        # 去除换行符后匹配(适配文件行尾的换行差异)
        stripped_line = line.rstrip('\n')
        if stripped_line not in delete_lines:
            out_fh.write(line)

2. 批量读取进一步提升效率

如果内存充足(450MB文件对现代机器无压力),采用批量读取减少IO次数:

month_file = "2015-01.nml.txt"
output_file = 'myfile_faster.xml'

delete_lines = {
        '<?xml version="1.0" encoding="ISO-8859-1" ?>',
        '<?xml version="1.0" encoding="iso-8859-1" ?>',
        '<!DOCTYPE doc SYSTEM "djnml-1.0b.dtd">',    
    } 

# 定义批量读取块大小(比如64MB,可根据内存调整)
BLOCK_SIZE = 64 * 1024 * 1024

with open(month_file, encoding="ISO-8859-1") as in_fh, open(output_file, 'w', encoding="ISO-8859-1") as out_fh:
    while True:
        block = in_fh.read(BLOCK_SIZE)
        if not block:
            break
        # 按换行分割块,处理每一行
        lines = block.split('\n')
        filtered_lines = [line for line in lines if line not in delete_lines]
        # 拼接后写入,注意补全换行符
        out_fh.write('\n'.join(filtered_lines) + '\n')

3. 正则匹配处理复杂场景(可选)

如果待过滤行存在空格、大小写等细微差异,预编译正则表达式提升匹配速度:

import re

month_file = "2015-01.nml.txt"
output_file = 'myfile_faster.xml'

# 预编译正则,忽略大小写和前后空格,匹配目标行
pattern = re.compile(
    r'^\s*(<\?xml version="1\.0" encoding="iso-8859-1"\s*\?>|<!DOCTYPE doc SYSTEM "djnml-1\.0b\.dtd">)\s*$',
    re.IGNORECASE
)

with open(month_file, encoding="ISO-8859-1") as in_fh, open(output_file, 'w', encoding="ISO-8859-1") as out_fh:
    for line in in_fh:
        if not pattern.match(line):
            out_fh.write(line)

4. 二进制模式读写(极致优化)

若无需处理编码转换,用二进制模式跳过文本编码/解码步骤,速度会大幅提升:

month_file = "2015-01.nml.txt"
output_file = 'myfile_faster.xml'

# 转换为字节串,包含换行符(适配文件行尾)
delete_bytes = {
    b'<?xml version="1.0" encoding="ISO-8859-1" ?>\n',
    b'<?xml version="1.0" encoding="iso-8859-1" ?>\n',
    b'<!DOCTYPE doc SYSTEM "djnml-1.0b.dtd">\n',
    # 兼容无换行的情况
    b'<?xml version="1.0" encoding="ISO-8859-1" ?>',
    b'<?xml version="1.0" encoding="iso-8859-1" ?>',
    b'<!DOCTYPE doc SYSTEM "djnml-1.0b.dtd">',
}

with open(month_file, 'rb') as in_fh, open(output_file, 'wb') as out_fh:
    for line in in_fh:
        if line not in delete_bytes:
            out_fh.write(line)

效果预期

仅修复“频繁打开输出文件”这一问题,处理速度即可提升几十倍,单个文件处理时间可降至几分钟内;结合批量读取或二进制模式,速度还能进一步优化。

内容的提问来源于stack exchange,提问作者Nishant Das

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 10:05:38