如何直接将ElementTree写入ZIP并保留UTF-8格式的XML声明?
解决ElementTree直接写入ZIP文件时保留正确UTF-8 XML声明的问题
你的问题核心在于对ElementTree.tostring()和write()方法的参数细节没完全掌握——其实不需要临时文件,只要正确设置参数就能直接生成带正确XML声明的字节流,写入ZIP文件。
为什么之前的方法失效?
- 方法1:你没有显式设置
xml_declaration=True参数,tostring()默认不会主动添加XML声明(除非编码不是UTF-8/utf-8),所以生成的XML缺少声明。 - 方法2:
encoding='utf8'会让生成的XML声明里的编码值变成utf8,不符合你需要的UTF-8或utf-8规范。 - 方法3:虽然可行,但磁盘IO确实会拖慢性能,完全可以用内存缓冲区替代。
解决方案1:修正tostring()参数
直接给tostring()添加xml_declaration=True参数,同时指定encoding='UTF-8',就能生成带正确声明的字节串,直接写入ZIP:
import os import tempfile import zipfile from xml.etree.ElementTree import Element, ElementTree, parse, tostring # (保留你原代码中的准备逻辑,包括生成src.zip和解析更新XML的部分) with zipfile.ZipFile(trgt_appr1_zip, 'a') as trgt1_zip: for xml_name, updated_tree in updated_trees: # 正确写法:显式指定xml_declaration=True byte_representation = tostring( element=updated_tree.getroot(), encoding='UTF-8', method='xml', xml_declaration=True # 关键参数,必须显式设为True ) trgt1_zip.writestr(zinfo_or_arcname=xml_name, data=byte_representation)
这样生成的XML会包含正确的声明:<?xml version='1.0' encoding='UTF-8'?>。
解决方案2:用内存缓冲区(BytesIO)替代临时文件
如果你更习惯用ElementTree.write()方法(比如需要更复杂的输出控制),可以用io.BytesIO在内存中生成XML内容,再写入ZIP,完全避免磁盘操作:
import io import os import tempfile import zipfile from xml.etree.ElementTree import Element, ElementTree, parse # (保留你原代码中的准备逻辑) with zipfile.ZipFile(trgt_appr1_zip, 'a') as trgt1_zip: for xml_name, updated_tree in updated_trees: buffer = io.BytesIO() # 用write()写入内存缓冲区,指定正确的编码和声明 updated_tree.write( buffer, encoding='UTF-8', method='xml', xml_declaration=True ) # 将缓冲区指针移到开头,读取字节内容 buffer.seek(0) trgt1_zip.writestr(xml_name, buffer.read())
这个方法和write()到临时文件的效果完全一致,但所有操作都在内存中完成,性能和方法1相当。
验证结果
你可以用Linux的file工具检查生成的ZIP中的XML文件,会显示UTF-8 Unicode text,同时查看文件内容会看到正确的XML声明。
内容的提问来源于stack exchange,提问作者trowek
相关产品推荐
相关产品推荐

