【问题标题】:Split 1GB Xml file using Java使用 Java 拆分 1GB 的 XML 文件
【发布时间】:2011-07-07 09:34:56
【问题描述】:

我有一个 1GB 的 Xml 文件,如何使用 Java 将其拆分为格式良好、尺寸更小的 Xml 文件?

这是一个例子:

<records>
  <record id="001">
    <name>john</name>
  </record>
 ....
</records>

谢谢。

【问题讨论】:

  • 这取决于您处理的 XML 类型。
  • 也许您可以发布一个小示例来描述您的文件以及您希望如何拆分它。因为正如 larsmans 提到的,这在很大程度上取决于它的结构以及小块的外观。
  • 这样 john....
  • 无论是 SAX(显而易见的选择)还是一些多 GB 64 位 java 和享受你的 DOM
  • 使用 vtd-xml,总代码行数可能会低于 15。

标签: java xml


【解决方案1】:

对于这种情况,我会使用 StAX 解析器。它将防止一次将整个文档读入内存。

  1. 将 XMLStreamReader 推进到子片段的本地根元素。
  2. 然后您可以使用 javax.xml.transform API 从这个 XML 片段生成一个新文档。这会将 XMLStreamReader 推进到该片段的末尾。
  3. 对下一个片段重复第 1 步。

代码示例

对于以下 XML,将每个“语句”部分输出到以“帐户属性值”命名的文件中:

<statements>
   <statement account="123">
      ...stuff...
   </statement>
   <statement account="456">
      ...stuff...
   </statement>
</statements>

这可以通过以下代码完成:

import java.io.File;
import java.io.FileReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class Demo {

    public static void main(String[] args) throws Exception  {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
        xsr.nextTag(); // Advance to statements element

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) {
            File file = new File("out/" + xsr.getAttributeValue(null, "account") + ".xml");
            t.transform(new StAXSource(xsr), new StreamResult(file));
        }
    }

} 

【讨论】:

  • 当我们可以直接从 XMLStreamReader 到 XMLStreamWriter 的管道时,为什么要涉及 javax.xml.transform,在每个记录元素之间滚动到一个新文件?
  • 是的,这是热门提示,只需将它们“管道”在一起,偶尔“关闭”并每隔 N 条记录重新打开 XMLStreamWriter。
  • 无法转换 javax.xml.transform.stax.StAXSource 类型的 Source ??
  • @Beta033 - 您使用的是什么版本的 JDK。我只是按原样重新运行代码,它工作得非常好。我正在为 Mac 使用 Oracle JDK 1.7.0。
  • @Somu 我确实必须将while 循环更改为while (xsr.isStartElement() || xsr.nextTag() == XMLStreamConstants.START_ELEMENT) 并在while 循环之前添加一个额外的xsr.nextTag()。也许这也对你有用?问题是子片段转换也前进到下一个元素,因此nextTag() 移动了一层太深。
【解决方案2】:

试试这个,使用 Saxon-EE 9.3。

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:mode streamable="yes"/>
    <xsl:template match="record">
      <xsl:result-document href="record-{@id}.xml">
        <xsl:copy-of select="."/>
      </xsl:result-document>
    </xsl:template>
</xsl:stylesheet>

该软件不是免费的,但如果它可以为您节省一天的编码时间,您就可以轻松证明投资的合理性。 (为推销道歉)。

【讨论】:

    【解决方案3】:

    DOM、Stax、SAX 都可以,但各有利弊。

    1. 在 DOM 的情况下,您不能将所有数据都放在内存中。
    2. 在 DOM、Stax 和 SAX 的情况下,编程控制更容易。
    3. 结合使用 SAX 和 DOM 是更好的选择。
    4. 使用已经执行此操作的框架可能是最佳选择。看看smooks。http://www.smooks.org

    希望对你有帮助

    【讨论】:

      【解决方案4】:

      我非常不同意 Blaise Doughan 的观点。 SAX 不仅难以使用,而且非常缓慢。使用 VTD-XML,您不仅可以使用 XPath 简化处理逻辑(非常常见的 10 倍代码缩减),而且速度更快,因为没有冗余的编码/解码转换。下面是带有 vtd-xml 的 java 代码

      import java.io.FileOutputStream;
      import com.ximpleware.*; 
      
      public class split {
          public static void main(String[] args) throws Exception {       
              VTDGen vg = new VTDGen();       
              if (vg.parseHttpUrl("c:\\xml\\input.xml", true)) {
                  VTDNav vn = vg.getNav();
                  AutoPilot ap = new AutoPilot(vn);
                  ap.selectXPath("/records/record");
                  int i=-1,j=0;
                  while ((i = ap.evalXPath()) != -1) {
                  long l=vn.getElementFragment();
                      (new FileOutputStream("out"+j+".xml")).write(vn.getXML().getBytes(), (int)l,(int)(l>>32));
                      j++;
                  }
              }
          }
      }
      

      【讨论】:

      • 我的建议是使用 StAX 而不是 SAX。此外,来自 VTD-XML FAQ (vtd-xml.sourceforge.net/faq.html) 问题中提到的 1GB 文件大小是 VTD-XML 处理命名空间限定 XML 范围的上限。
      • StAX 和 SAX 之间没有显着的性能差异。两者都尽可能快。然而,有些人可能会发现 StAX 更易于使用 - 使用像 SAX 这样的基于事件的编程模型需要更多的编程成熟度。
      • 在没有命名空间支持的情况下,vtd-xml 支持的文件大小最大为 2GB。扩展 VTD-XML 的文件大小限制为 256 GB,即使支持命名空间。
      • 这是您的代码中的一部分(VTDGen.parseFile() 方法):fis = new FileInputStream(f); byte[] b = new byte[(int) f.length()];。因此,您将所有文件加载到内存中。这真是令人作呕。
      • @vtd-xml-author OP 没有提到需要运行的环境类型。但如果它是多用户环境并且每个用户都可能运行此代码,那么 4 GB 机器最多允许 4 个用户像这样分割一个 1 GB 的文件。这可能还不够。
      猜你喜欢
      • 2015-05-23
      • 2011-09-12
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      相关资源
      最近更新 更多