`
guohf
  • 浏览: 417726 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

dom4j处理大文件

阅读更多

前几天因为个人爱好,学习在Java中处理XML文档。java是开源的,自然用于处理xml的技术也是满天星斗,在网上奔波了数十分钟最终决定使用dom4j。对于入门的使用就像是羊粑粑沥漏落落满天星,很快掌握。可是当读写的xml文档稍大时这些代码就经受不住考验了,一个老问题内存溢出。这说明网上大部分的代码是将xml文档全部读入内存进行操作或是在内存中建立完整的xml文档再一次性的写入文件。有办法了,求助于网络,百度、 google搜了便,可结果是城市的天空根本看不见星星。更有为数不少的人得出结论,使用dom4j操作xml文档时受到文件大小的限制(纯属谬论),那么多的高手开发出的dom4j会考虑不到大文件的问题?求人不如求己,虽然本人英语其差(大学英语4级290分),还是决定上官方网站寻求答案(www.dom4j.org)。刚登录就在常见问题中看到了下面的问题
How does dom4j handle very large XML documents?(该句中80%的单词我还是认识的)
下面是本人的理解英语好的人应该去看英文原版,不要看我的垃圾翻译。
­
dom4j提供了基于事件的模型来操作xml文档。利用该模型开发人员可以一部分、一部分的处理XML文档,而不需要将整个XML文档都加载到内存中。例如:假想你要处理一个非常大的XML文档,它可能是由数据库的某张数据表而来的。如下所示:
<ROWSET>
<ROW ID="1">
  ...
</ROW>
<ROW ID="2">
  ...
</ROW>
...
<ROW ID="N">
  ...
</ROW>
</ROWSET>
我们可以在某一时间只处理一个ROW节点,而不必立刻将文档的所有内容加载到内存中。dom4j提供一个基于事件的模型来实现它。我们可以注册一个事件处理器来处理一个或多个路径表达式。事件处理器会在注册路径的开始和结束时被调用执行。当注册路径的开始标签找到时执行事件处理器的 onStart()方法,当注册路径的结束标签被找到时执行事件处理器的onEnd()方法。
­
onStart()和onEnd()方法传递一个ElementPath实例参数,这个实例既为根据注册路径遍历xml文档时的当前节点(Element)。如果想对遍历的当前节点进行操作,可以在onEnd()方法中对当前节点调用detach()方法保存改。
下面是示例代码: 
 

SAXReader reader = new SAXReader(); 
reader.addHandler( "/ROWSET/ROW", 
    new ElementHandler() { 
        public void onStart(ElementPath path) { 
            // do nothing here...     
        } 
        public void onEnd(ElementPath path) { 
            // process a ROW element 
            Element row = path.getCurrent(); 
            Element rowSet = row.getParent(); 
            Document document = row.getDocument(); 
            ... 
            // prune the tree 
            row.detach(); 
        } 
    } 
); 

  
Document document = reader.read(url);
上面的办法解决了读的问题可是写的问题还没有解决。我命由我不由天(吹牛皮),畅游dom4j的doc文档找到如下几个方法
startDocument()
writeOpen();
writeClose();
endDocument()
动手一试,问题搞定,看来牛皮没白吹。下面是示例代码: 
 

/** 
  * 数据写入xml文件 
  * @param filePath 目标xml文件的存放路径 
  * @return 
  */ 
public boolean writeXML(String filePath){ 
  XMLWriter out; 
  try { 
   
   /* 
    * 创建XMLWriter对象,设置XML编码,解决中文问题。 
    */ 
   OutputFormat outputFormat = OutputFormat.createPrettyPrint(); 
   outputFormat.setEncoding("GBK"); 
   out = new XMLWriter(new FileWriter(filePath),outputFormat); 
   
   
   out.startDocument(); 
   Element rootElement = DocumentHelper.createElement("mans"); 
   out.writeOpen(rootElement); 
   
   /* 
    * 向mans节点写入子节点 
    */ 
   for(int i=0 ; i<1000000 ; i++){ 
    Element man = createManElement(new Long(i), "shuhang"+i);//用于创建节点的方法 
    out.write(man); 
    System.out.println(" the loop index is : " + i); 
   } 
   
   out.writeClose(rootElement); 
   out.endDocument(); 
   
   out.close(); 
   return true; 
  } catch (IOException e) { 
   e.printStackTrace(); 
   return false; 
  } catch (SAXException e) { 
   e.printStackTrace(); 
   return false; 
  } 
} 

  
­
新问题出现。对于读取数据的方法,在onEnd()方法中只是进行对Element的简单操作而已,若要对Element进行复杂的处理怎么办,如将Element节点的数据写入数据库,无法在onEnd()方法中加入过多的代码,因为无法通过编译。仔细想了一下dom4j的注册事件处理器应该用的是模板方法,通过钩子将用户的操作加入到模板中去。何不自己写一个事件处理器来完成我们自己的定制操作,代码如下: 
 
 

public class ManElementHandler implements ElementHandler { 
public String mdbName; 
­
public ManElementHandler(){ 
   
} 
­
public ManElementHandler(String mdbName){ 
  this.mdbName = mdbName; 
} 
­
public boolean saveMan(Element element, String mdbName){ 
  return true; 
} 
­
public void onEnd(ElementPath arg0) { 
         Element row = arg0.getCurrent(); 
         Element rowSet = row.getParent(); 
         Document document = row.getDocument(); 
         Element root = document.getRootElement(); 
  Iterator it = root.elementIterator(); 
  while(it.hasNext()){ 
   Element element = (Element)it.next(); 
   System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name")); 
   saveMan(element, this.mdbName); 
  } 
         row.detach(); 
} 
public void onStart(ElementPath path) { 
   
} 
} 

  
下面给出完整的实例代码。该实例首先创建一个xml文档,然后读取xml文档中的数据并将数据写入Access数据库中。测试时使用的文件大小为125M未发生内存溢出。
 
//*****************************************************************************************************************

package com; 
import java.sql.Connection; 
import java.sql.DriverManager; 
/** 
* 获取Access数据库的连接 
* @author 佛山无影脚 
* @version 1.0 
* Jul 7, 2008  4:35:49 PM 
*/ 
public class AccessMDBUtil { 
public static Connection connectMdb(String mdbName) { 
  if(mdbName == null || mdbName.equals("")){ 
   return null; 
  } 
  try { 
   Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 
   String dburl ="jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ="+mdbName; 
   Connection conn=DriverManager.getConnection(dburl); 
   return conn; 
  } catch (Exception e) { 
   e.printStackTrace(); 
   return null; 
  } 
} 
} 

 //*******************************************************************************************************************

package com; 
import java.sql.Connection; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Statement; 
import java.util.Iterator; 
import org.dom4j.Document; 
import org.dom4j.Element; 
import org.dom4j.ElementHandler; 
import org.dom4j.ElementPath; 
/** 
* 定制的事件处理器 
* @author 佛山无影脚 
* @version 1.0 
* Jul 7, 2008  4:35:49 PM 
*/ 
public class ManElementHandler implements ElementHandler { 
public String mdbName;//数据库名称 含路径 
­
public ManElementHandler(){ 
   
} 
­
public ManElementHandler(String mdbName){ 
  this.mdbName = mdbName; 
} 
­
/** 
  *将Element节点数据保存到数据库 
  *@param element 遍历XML文档时的当前节点 
  *@param mdbName 数据库名称 含路径 
  *@return 
  */ 
public boolean saveMan(Element element, String mdbName){ 
  System.out.println(" the method saveMan in ManElementHandler is execute!"); 
  Statement stmt = null; 
  ResultSet rs = null; 
  Connection conn = null; 
  try { 
   conn= AccessMDBUtil.connectMdb(mdbName); 
   stmt=conn.createStatement(); 
   String sql = "insert into mans(id,name) values(" + element.elementText("id") + ",'" + element.elementText("name") + "')"; 
   stmt.executeUpdate(sql); 
   
  } catch (Exception e) { 
   e.printStackTrace(); 
   return false; 
  } finally { 
   if(rs != null) { 
    try { 
     rs.close(); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
   } 
   if(stmt != null) { 
    try { 
     stmt.close(); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
   } 
   if(conn != null) { 
    try { 
     conn.close(); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
   } 
   
  } 
   
  return true; 
} 
­
public void onEnd(ElementPath arg0) { 
         Element row = arg0.getCurrent(); 
         Element rowSet = row.getParent(); 
         Document document = row.getDocument(); 
         Element root = document.getRootElement(); 
  Iterator it = root.elementIterator(); 
  while(it.hasNext()){ 
   Element element = (Element)it.next(); 
   System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name")); 
   saveMan(element, this.mdbName); 
  } 
          row.detach(); 
} 
public void onStart(ElementPath path) { 
   
} 
} 

 //*************************************************************************************************************************

package com; 
import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import org.dom4j.Document; 
import org.dom4j.DocumentException; 
import org.dom4j.DocumentHelper; 
import org.dom4j.Element; 
import org.dom4j.io.OutputFormat; 
import org.dom4j.io.SAXReader; 
import org.dom4j.io.XMLWriter; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 
/** 
* 测试 
* @author 佛山无影脚 
* @version 1.0 
* Jul 7, 2008  4:35:49 PM 
*/ 
public class ManTest { 
/** 
  * 创建man节点 
  * <man><id>1</id><name>佛山无影脚</name></man> 
  * @param id 
  * @param name 
  * @return 
  */ 
public Element createManElement(Long id,String name){ 
  Element manElement = DocumentHelper.createElement("man"); 
  manElement.addElement("id").addText(id.toString()); 
  manElement.addElement("name").addText(name); 
  return manElement; 
} 
­
/** 
  * 数据写入xml文件 
  * @param filePath 目标xml文件的存放路径 
  * @return 
  */ 
public boolean writeXML(String filePath){ 
  XMLWriter out; 
  try { 
   
   /* 
    * 创建XMLWriter对象,设置XML编码,解决中文问题。 
    */ 
   OutputFormat outputFormat = OutputFormat.createPrettyPrint(); 
   outputFormat.setEncoding("GBK"); 
   out = new XMLWriter(new FileWriter(filePath),outputFormat); 
   
   
   out.startDocument(); 
   Element rootElement = DocumentHelper.createElement("mans"); 
   out.writeOpen(rootElement); 
   
   /* 
    * 向mans节点写入子节点 
    */ 
   for(int i=0 ; i<1000000 ; i++){ 
    Element man = this.createManElement(new Long(i), "shuhang"+i); 
    out.write(man); 
    System.out.println(" the loop index is : " + i); 
   } 
   
   out.writeClose(rootElement); 
   out.endDocument(); 
   
   out.close(); 
   return true; 
  } catch (IOException e) { 
   e.printStackTrace(); 
   return false; 
  } catch (SAXException e) { 
   e.printStackTrace(); 
   return false; 
  } 
} 
­
/** 
  * 从xml文件中读取数据,并将数据写入Access数据 
  * @param filePath xml文件的存放路径 
  * @return 
  */ 
public boolean readXML(String filePath){ 
   
  ManElementHandler manElementHandler = new ManElementHandler("F:\\dom4j\\xmlTest.mdb"); 
  SAXReader reader = new SAXReader(); 
  reader.addHandler( "/mans/man", manElementHandler); 
  Document document = null; 
     try { 
      File file = new File(filePath); 
   document = reader.read(file); 
  } catch (DocumentException e) { 
   e.printStackTrace(); 
   return false; 
  } 
  return true; 
} 
­
­
public static void main(String[] args){ 
  XMLReader reader = null; 
  long startTime = System.currentTimeMillis(); 
  ManTest mantest = new ManTest(); 
   
  mantest.writeXML("f:\\dom4j\\mans.xml"); 
  mantest.readXML("f:\\dom4j\\mans.xml"); 
   
  long endTime = System.currentTimeMillis(); 
  System.out.println(" is end! the millis is : " + (endTime - startTime)); 
   
} 
} 

 

分享到:
评论

相关推荐

    dom4j 解析 大 文件

    在处理大文件时,DOM4J结合XPath的使用,可以有效地管理和分析大量数据。在这个场景下,描述提到的测试涉及到了50多万条数据的解析,这无疑是对DOM4J性能的一次挑战。 首先,我们来深入理解DOM4J的核心概念。DOM4J...

    dom4j解析xml文件的压缩包

    5. **事件驱动解析(SAX)**:除了传统的DOM解析外,DOM4J还支持SAX解析器,这种解析方式适用于处理大型XML文件,因为它不需要一次性加载整个文档到内存。 6. **Namespace支持**:DOM4J提供了对XML命名空间的全面...

    dom4j读取大文件的缓存方式

    总结来说,这些文件共同展示了如何利用DOM4J库处理大文件,尤其是通过SAX解析和事件处理来避免内存溢出问题。在实际开发中,对于大文件的XML处理,使用这样的策略能够提高程序的稳定性和效率,同时减少对系统资源的...

    DOM4J jar包 xml解析 所有的dom4j-1.6.1 dom4j-2.0.2 dom4j-2.1.1包 导入直接使用

    6. **StAX(Streaming API for XML)支持**:DOM4J也支持StAX解析器,这种解析方式结合了SAX的高效和DOM的易用性,可以在处理大型XML文件时节省内存。 7. **与JAXB集成**:DOM4J可以与Java Architecture for XML ...

    dom4j dom4j dom4j dom4j

    在Java世界中,DOM4J是与DOM、SAX和JDOM等其他XML处理库并驾齐驱的一个选择,尤其在处理大型XML文件时,其性能和内存效率往往更胜一筹。 DOM4J的主要特点包括: 1. **丰富的API**:DOM4J提供了大量的接口和类,...

    使用dom4j 和本地dom 解析xml 文件

    XML(eXtensible Markup Language)是一种用于标记数据的语言,广泛...在Java开发中,根据XML文件的大小和处理需求,可以选择DOM4J以获得更好的性能和便利性。理解并熟练掌握这两种解析技术,对于处理XML数据至关重要。

    分别使用DOM和DOM4j解析XML文件

    本篇文章将详细介绍如何使用DOM(Document Object Model)和DOM4j这两种流行的方法来解析XML文件。 首先,DOM是一种标准的W3C推荐的解析XML的方法,它将整个XML文档加载到内存中,形成一个树形结构,便于程序进行...

    dom4j解析xml文件(增删改查)

    在“dom4j解析xml文件(增删改查)”这个主题中,我们将深入探讨如何使用DOM4J来实现XML文档的四种基本操作:增加元素、删除元素、更新元素内容以及查询元素。 首先,让我们了解DOM4J的基本用法。在解析XML文件时,...

    dom4j_dom4j1.6.1安装包_

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了灵活、高效的API,使得XML的解析、创建、查询和修改变得更为简单。在本文中,我们将深入探讨DOM4J 1.6.1版本的安装及其在Maven项目中的应用。 首先,DOM4J...

    使用Maven管理项目,实现DOM4j操作XML文件

    DOM4j则是一个强大的Java库,用于处理XML文档,提供了丰富的API来实现XML的读取、写入、修改等操作。在这个示例中,我们将深入探讨如何利用Maven管理和DOM4j来操作XML文件。 首先,让我们了解一下Maven。Maven是...

    dom4j_1.6.1.jar dom4j_2.1.0.jar

    这个列表只包含了一个条目"xml",可能意味着压缩包中包含的是与XML相关的文件或资源,可能是XML示例文件、测试用例或者与DOM4J处理XML相关的配置文件。 总结来说,DOM4J是一个强大的XML处理库,提供了丰富的API和...

    dom4j读写xml文件

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了灵活且高效的API,使得XML的读取、创建、修改和解析变得简单易行。在本文中,我们将深入探讨DOM4J如何实现XML文件的读取和写入,并通过一个实际的`...

    dom4j-2.1.3.zip

    首先,DOM4J的核心在于其对DOM模型的优化,使得在处理大型XML文件时性能更优,内存占用更低。在"dom4j-2.1.3.jar"文件中,包含了DOM4J库的所有类和方法,可以用于构建、解析和操作XML文档。这个版本的DOM4J在前一...

    dom4j文件下载

    4. **事件驱动解析:**除了DOM解析,DOM4J也支持SAX解析器,允许在处理大型XML文件时节省内存。 5. **流式处理:**DOM4J还支持StAX解析,适用于处理大量数据或需要低内存占用的情况。 6. **XML编组和解组:**DOM4J...

    dom4j解析xml文件必备jar包

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了灵活且高效的API,使得XML的解析、创建、查询和修改变得简单。DOM4J在Java社区中被广泛使用,尤其是在那些需要处理大量XML数据的应用中。这个压缩包包含了...

    dom4j解析xml文件代码示例

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了灵活且高效的API,使得XML的解析、创建、修改和查询变得简单。在本示例中,我们将深入探讨如何使用DOM4J解析XML文件,以`CacheInit.java`作为我们的核心代码...

    dom4j dom4j1.6 dom4j最新版

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了灵活且高效的API,使得XML的解析、创建、修改和查询变得简单。DOM4J 1.6是该库的一个较新版本,提供了完整的功能集以及对XML标准的广泛支持。 DOM4J的核心...

    dom4j的Java工程

    通过研究其中的代码,你可以掌握DOM4J处理XML的基本技巧,并理解如何将其应用到实际的Java项目中,以实现XML文件的高效管理和操作。无论是新手还是有经验的开发者,都能从中受益匪浅,提升对XML处理的能力。

    dom4j所依赖的所有jar包

    DOM4J是一个强大的Java库,专门用于处理XML文档。它提供了简单而直观的API,使得开发者可以方便地读取、写入、修改以及操作XML文件。DOM4J 1.6.1是这个库的一个稳定版本,发布于较早时期,但依然广泛应用于许多Java...

Global site tag (gtag.js) - Google Analytics