java - 如何使用 STAX api 处理大型 XML 文件 (9 GB)

标签 java xml io stream stax

在处理大文件时,我总是遇到堆内存问题。这里我正在处理 9 GB 的 xml 文件。

这是我的代码。

            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            InputStream in = new FileInputStream(sourcePath);
            XMLEventReader eventReader =  inputFactory.createXMLEventReader(in);

            Map<String, Cmt> mapCmt = new ConcurrentHashMap<String, Cmt>();
            while (eventReader.hasNext()) {
                XMLEvent event = eventReader.nextEvent();
                if (event.isStartElement()) {
                //some processing and assigning value to map
                Cmt cmt = new Cmt();
                //get attributes
                cmt.setDetails(attribute.getValue());
                mapCmt.put(someKey,cmt);
                }
            }

一段时间后,我在迭代中遇到堆内存问题。 请帮助我编写优化的代码。

注意:服务器有 3 GB 可用堆空间。我无法增加服务器空间。 我正在使用以下参数执行 -Xms1024m -Xmx3g

我的 xml 看起来像这样。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<DatosAbonados xmlns="http://www.cnmc.es/DatosAbonados">
    <DatosAbonado Operacion="1" FechaExtraccion="2015-10-08">
        <Titular>
            <PersonaJuridica DocIdentificacionJuridica="A84619488" RazonSocial="HERMANOS ROJAS" NombreComercial="PINTURAS ROJAS"/>
        </Titular>
        <Domicilio Escalera=" " Piso=" " Puerta=" " TipoVia="AVENIDA" NombreVia="MANOTERAS" NumeroCalle="10" Portal=" " CodigoPostal="28050" Poblacion="Madrid" Provincia="28"/>
        <NumeracionAbonado>
            <Rangos NumeroDesde="211188600" NumeroHasta="211188699" ConsentimientoGuias-Consulta="1" VentaDirecta-Publicidad="1" ModoPago="1">
                <Operador RazonSocial="11888 SERVICIO CONSULTA TELEFONICA S.A." DocIdentificacionJuridica="A83519389"/>
            </Rangos>
        </NumeracionAbonado>
    </DatosAbonado>
    <DatosAbonado Operacion="1" FechaExtraccion="2015-10-08">
        <Titular>
            <PersonaJuridica DocIdentificacionJuridica="A84619489" RazonSocial="HERMANOS RUBIO" NombreComercial="RUBIO PELUQUERIAS"/>
        </Titular>
        <Domicilio Escalera=" " Piso=" " Puerta=" " TipoVia="AVENIDA" NombreVia="BURGOS" NumeroCalle="18" Portal=" " CodigoPostal="28036" Poblacion="Madrid" Provincia="28"/>
        <NumeracionAbonado>
            <Rangos NumeroDesde="211186000" NumeroHasta="211186099" ConsentimientoGuias-Consulta="1" VentaDirecta-Publicidad="1" ModoPago="1">
                <Operador RazonSocial="11888 SERVICIO CONSULTA TELEFONICA S.A." DocIdentificacionJuridica="A83519389"/>
            </Rangos>
        </NumeracionAbonado>
    </DatosAbonado>
</DatosAbonados>

我的 Cmt 类(class)是:

public class Cmt {
    private List<DetailInfo> details;

    public List<DetailInfo> getDetails() {
        return details;
    }
    public void setDetails(DetailInfo detail) {
        if(details == null){
            details = new ArrayList<DetailInfo>();
        }
        this.details.add(detail);
    }
}

Actually Cmt object is very less, But i have DetailInfo object for every element. So huge no. of DetailInfo object is created.

我的逻辑是这样的:

if (startElement.getName().getLocalPart().equals("DatosAbonado")) {
                    detailInfo = new DetailInfo();

                    Iterator<Attribute> attributes = startElement.getAttributes();
                    while (attributes.hasNext()) {
                        Attribute attribute = attributes.next();
                         if(attribute.getName().toString().equals("Operacion")){
                            detailInfo.setOperacion(attribute.getValue());
                        }
                    }
                }
if (event.isEndElement()) {
                EndElement endElement = event.asEndElement();
                if (endElement.getName().getLocalPart().equals("DatosAbonado")) {
                    Cmt cmt = null;
                    if(mapCmt.keySet().contains(identificador)){
                        cmt = mapCmt.get(identificador);
                    } else{
                        cmt = new Cmt();
                    }
                    cmt.setDetails(detailInfo);
                    mapCmt.put(identificador, cmt);
}
}

最佳答案

您的问题的根源很可能是这样的:

mapCmt.put(someKey, cmt);

您正在使用许多大型 Cmt 对象填充 HashMap 。您需要执行以下操作之一:

  • 立即处理数据,而不是将其保存在数据结构中。
  • 将数据写入数据库以供以后查询。
  • 增加堆大小。
  • 为您的数据找出一种“内存消耗较少”的表示方式。

最后两种方法无法扩展。随着输入文件大小的增加,您将需要逐渐更多的内存......直到最终超出执行平台的内存容量。

关于java - 如何使用 STAX api 处理大型 XML 文件 (9 GB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33518452/

相关文章:

xml - Grails 3-具有XML的Marshaller

java - 如何在不使用非 api 类的情况下取消 Java 中的 Files.copy() ?

java - 如何为嵌入式 Neo4j 数据库执行 Gremlin 脚本?

java - 带正则表达式的 MaskFormatter

xml - XPath选择没有“isNull”的值

java - 从 xml 字符串中删除非法标记(以数字开头的节点)

validation - Haskell IO,在同一行中获取两个输入并进行验证

java - I/O 上的事件处理

java - openjfx中的SwingNode类导致问题

java - 将文件包含在具有不同名称的 war 中的简洁方法