如何优化代码处理150MB大型XML文件去重?小文件代码已实现
针对大型XML文件的去重解决方案
问题分析
你当前使用DOMDocument的代码会将整个XML文件加载到内存中,对于150MB的大文件来说,必然会导致内存占用过高甚至溢出,这是无法适配大文件场景的核心原因。此外,原代码通过三个数组分别存储字段值、遍历匹配重复项的逻辑,效率也偏低。
解决方案:流式XML解析(XMLReader)
采用PHP的XMLReader类实现流式解析,它会逐节点读取XML内容,无需将整个文档加载到内存,完美适配大文件处理场景。我们可以将t__thl__usa、t__p__city、t__p__province三个标签的组合值作为唯一键存入哈希集合,遇到重复组合就跳过输出,否则保留并记录该组合。
高效实现代码
<?php $inputFile = 'xml/in/100values.xml'; $outputFile = 'xml/out/duplicates_removed.xml'; $reader = new XMLReader(); $writer = new XMLWriter(); if (!$reader->open($inputFile)) { die('无法打开输入XML文件'); } $writer->openUri($outputFile); $writer->startDocument('1.0', 'UTF-8'); $writer->setIndent(true); $seen = []; // 存储已出现的字段组合键 // 定位并写入根节点 while ($reader->read() && $reader->nodeType !== XMLReader::ELEMENT); $writer->startElement($reader->name); // 遍历根节点下的所有数据项 while ($reader->next() && $reader->depth === 1) { if ($reader->nodeType === XMLReader::ELEMENT) { $usa = ''; $city = ''; $province = ''; // 提取当前数据项的目标字段值 $subReader = new XMLReader(); $subReader->xml($reader->readOuterXml()); while ($subReader->read()) { if ($subReader->nodeType === XMLReader::ELEMENT) { switch ($subReader->name) { case 't__thl__usa': $usa = $subReader->readString(); break; case 't__p__city': $city = $subReader->readString(); break; case 't__p__province': $province = $subReader->readString(); break; } } } $subReader->close(); // 生成唯一组合键 $key = implode('|', [$usa, $city, $province]); // 非重复项则写入输出文件 if (!isset($seen[$key])) { $seen[$key] = true; $writer->writeRaw($reader->readOuterXml()); } } } $writer->endElement(); // 关闭根节点 $writer->endDocument(); $writer->flush(); $reader->close(); echo '去重完成,结果已保存到 ' . $outputFile; ?>
核心优势
- 内存友好:流式解析仅在内存中保留单个数据项的内容,处理150MB文件不会出现内存溢出问题。
- 效率提升:通过哈希数组直接判断组合是否存在,时间复杂度为O(1),比原代码的遍历匹配效率高得多。
- 结构兼容:保留原XML的结构和格式,仅去除重复的数据项,无需修改输出文件的节点层级。
内容的提问来源于stack exchange,提问作者Pranavmtn
相关产品推荐
相关产品推荐

