在将大量文件数据写入 XML 时减少内存 (RAM) 消耗的有效方法
Efficient way to reduce memory (RAM) consumption while writing huge file data into XML
我必须将 7 个列表写入 XML 文件,每个列表的大小为 1 GB 到 5 GB。
预计XML文件如下:
<doc>
<items1>
<itemA>..</itemA>
..
</items1>
<items2>
<itemB>..</itemB>
..
</items2>
<items3>
<itemC>..</itemC>
..
</items3>
.
.
.
<items7>
<itemG>..</itemG>
..
</items7>
</doc>
Java 对象如下:
List<ItemA> items1 = new List<>(); // 1GB-5GB
List<ItemB> items2 = new List<>(); // 1GB-5GB
List<ItemC> items3 = new List<>(); // 1GB-5GB
List<ItemD> items4 = new List<>(); // 1GB-5GB
List<ItemE> items5 = new List<>(); // 1GB-5GB
List<ItemF> items6 = new List<>(); // 1GB-5GB
List<ItemG> items7 = new List<>(); // 1GB-5GB
将所有列表包装到一个对象(目录)到一个 Java 对象中,并且一次编组会消耗大量内存,而且每当这个列表大小增加时,我们都必须扩展我们的基础设施。下面是代码:
JAXBContext.newInstance("ta").createMarshaller().marshal(new ObjectFactory().createCatalogue(catalogue), new FileOutputStream(fileName));
这里的 catalog 是一个包含所有七个列表的 Java 对象。
有什么聪明的方法可以通过分块写入数据来减少内存消耗。为此,我探索了 stax,但找不到写入数据列表的方法。
在 Java 中是否有任何方法可以有效地将最多 20 GB 写入 XML,而无需通过基础设施扩展 RAM?
我们想分别写每个列表,而且之前写的文件不应该在写下一个列表时加载到堆中。
使用 StAX 很可能是最好的方法,不仅因为您不必将整个 XML 文档保存在内存中,而且因为您也不必将所有 items 在内存中。不知道您在哪里寻找使用 StAX 编写的内容,但我在 The Java EE 5 Tutorial:
中找到了以下内容
The following example, taken from the StAX specification, shows how to
instantiate an output factory, create a writer, and write XML output:
XMLOutputFactory output = XMLOutputFactory.newInstance();
XMLStreamWriter writer = output.createXMLStreamWriter( ... );
writer.writeStartDocument();
writer.setPrefix("c","http://c");
writer.setDefaultNamespace("http://c");
writer.writeStartElement("http://c","a");
writer.writeAttribute("b","blah");
writer.writeNamespace("c","http://c");
writer.writeDefaultNamespace("http://c");
writer.setPrefix("d","http://c");
writer.writeEmptyElement("http://c","d");
writer.writeAttribute("http://c","chris","fry");
writer.writeNamespace("d","http://c");
writer.writeCharacters("Jean Arp");
writer.writeEndElement();
writer.flush();
This code generates the following XML (new lines are non-normative):
<?xml version=’1.0’ encoding=’utf-8’?>
<a b="blah" xmlns:c="http://c" xmlns="http://c">
<d:d d:chris="fry" xmlns:d="http://c"/>
Jean Arp
</a>
编辑: 我还注意到 generating XML with StAX in the link you posted 上有一个部分。另外,请注意“编写列表”没有什么特别之处,您只需遍历列表并为每个条目写一个标签。像这样:
XMLStreamWriter writer = ...;
writer.writeStartDocument();
writer.writeStartElement("doc");
// Write the first list:
writer.writeStartElement("items1");
for (ItemA e: items1) {
writer.writeStartElement("itemA");
// TODO: Write attributes, sub-elements, text or whatever is needed
writer.writeEndElement();
});
writer.writeEndElement();
// TODO: Write items2, items3, ..., items7 in the same fashion as items1
// Close document
writer.writeEndElement();
writer.writeEndDocument();
XMLStreamWriter 是低级的,这意味着除了将 XML 写入流之外,它不会为您做更多的事情,但它并不复杂。因此,与使用 JAXB 相比,您最终可能会多出几行代码,但您必须编写的代码不会特别难写。
我必须将 7 个列表写入 XML 文件,每个列表的大小为 1 GB 到 5 GB。
预计XML文件如下:
<doc>
<items1>
<itemA>..</itemA>
..
</items1>
<items2>
<itemB>..</itemB>
..
</items2>
<items3>
<itemC>..</itemC>
..
</items3>
.
.
.
<items7>
<itemG>..</itemG>
..
</items7>
</doc>
Java 对象如下:
List<ItemA> items1 = new List<>(); // 1GB-5GB
List<ItemB> items2 = new List<>(); // 1GB-5GB
List<ItemC> items3 = new List<>(); // 1GB-5GB
List<ItemD> items4 = new List<>(); // 1GB-5GB
List<ItemE> items5 = new List<>(); // 1GB-5GB
List<ItemF> items6 = new List<>(); // 1GB-5GB
List<ItemG> items7 = new List<>(); // 1GB-5GB
将所有列表包装到一个对象(目录)到一个 Java 对象中,并且一次编组会消耗大量内存,而且每当这个列表大小增加时,我们都必须扩展我们的基础设施。下面是代码:
JAXBContext.newInstance("ta").createMarshaller().marshal(new ObjectFactory().createCatalogue(catalogue), new FileOutputStream(fileName));
这里的 catalog 是一个包含所有七个列表的 Java 对象。
有什么聪明的方法可以通过分块写入数据来减少内存消耗。为此,我探索了 stax,但找不到写入数据列表的方法。
在 Java 中是否有任何方法可以有效地将最多 20 GB 写入 XML,而无需通过基础设施扩展 RAM?
我们想分别写每个列表,而且之前写的文件不应该在写下一个列表时加载到堆中。
使用 StAX 很可能是最好的方法,不仅因为您不必将整个 XML 文档保存在内存中,而且因为您也不必将所有 items 在内存中。不知道您在哪里寻找使用 StAX 编写的内容,但我在 The Java EE 5 Tutorial:
中找到了以下内容The following example, taken from the StAX specification, shows how to instantiate an output factory, create a writer, and write XML output:
XMLOutputFactory output = XMLOutputFactory.newInstance(); XMLStreamWriter writer = output.createXMLStreamWriter( ... ); writer.writeStartDocument(); writer.setPrefix("c","http://c"); writer.setDefaultNamespace("http://c"); writer.writeStartElement("http://c","a"); writer.writeAttribute("b","blah"); writer.writeNamespace("c","http://c"); writer.writeDefaultNamespace("http://c"); writer.setPrefix("d","http://c"); writer.writeEmptyElement("http://c","d"); writer.writeAttribute("http://c","chris","fry"); writer.writeNamespace("d","http://c"); writer.writeCharacters("Jean Arp"); writer.writeEndElement(); writer.flush();
This code generates the following XML (new lines are non-normative):
<?xml version=’1.0’ encoding=’utf-8’?> <a b="blah" xmlns:c="http://c" xmlns="http://c"> <d:d d:chris="fry" xmlns:d="http://c"/> Jean Arp </a>
编辑: 我还注意到 generating XML with StAX in the link you posted 上有一个部分。另外,请注意“编写列表”没有什么特别之处,您只需遍历列表并为每个条目写一个标签。像这样:
XMLStreamWriter writer = ...;
writer.writeStartDocument();
writer.writeStartElement("doc");
// Write the first list:
writer.writeStartElement("items1");
for (ItemA e: items1) {
writer.writeStartElement("itemA");
// TODO: Write attributes, sub-elements, text or whatever is needed
writer.writeEndElement();
});
writer.writeEndElement();
// TODO: Write items2, items3, ..., items7 in the same fashion as items1
// Close document
writer.writeEndElement();
writer.writeEndDocument();
XMLStreamWriter 是低级的,这意味着除了将 XML 写入流之外,它不会为您做更多的事情,但它并不复杂。因此,与使用 JAXB 相比,您最终可能会多出几行代码,但您必须编写的代码不会特别难写。