锁定老帖子 主题:大容量XML文件解析辅助--xml批量分解
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-07-10
个人水平有限,但很希望得到大家的指正,希望大家不吝啬手中的砖头 package searchRing.ring.util.xmlBufferTool; import java.io.*; import java.util.regex.Pattern; import java.util.regex.Matcher; public class XMLBufferTool { private static final int defaultLineCount = 10; private static final int defaultMaxOutputSize = 50; private static final Pattern elementPattern = Pattern.compile("<[a-zA-Z]+>"); private static final Pattern charSetPattern = Pattern.compile("<[?][[0-9a-zA-Z]|[\\s]|[=]|[\"]|[.]|[-]]+[?]>"); private StringBuffer xmlContentBuffer; /* just used to store and output the data divided */ XMLOutputBuffer xmlOutput; private String charSetTitle = ""; private String rootElemetMark = ""; private String childElementMark = ""; InputStreamReader bufferedReader; InputStream fileInputStream; public XMLBufferTool(String xmlFilePath) { this.xmlContentBuffer = new StringBuffer(); try { this.fileInputStream = new FileInputStream(xmlFilePath); // bufferedReader = new InputStreamReader(fileInputStream, "UTF-8"); String charSet = getCharSet(xmlFilePath); if (charSet != null) bufferedReader = new InputStreamReader(fileInputStream, charSet); else bufferedReader = new InputStreamReader(fileInputStream); } catch (FileNotFoundException fe) { fe.printStackTrace(); } catch (UnsupportedEncodingException uee) { uee.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } try { preparePaser(); } catch (IOException ie) { ie.printStackTrace(); } } public String getCharSetTitle() { return charSetTitle; } public String getRootElemetMark() { return rootElemetMark; } private String getCharSet(String filePath) throws IOException { char temp[] = new char[512]; FileInputStream tempInput = new FileInputStream(filePath); InputStreamReader tempReader = new InputStreamReader(tempInput); int i = tempReader.read(temp); tempReader.close(); tempInput.close(); if (i < 0) return null; String tempStr = new String(temp); Matcher m = charSetPattern.matcher(tempStr); if (m.find()) { String charSetStr = tempStr.substring(m.start(), m.end()); Pattern tempP = Pattern.compile("[\"][[0-9a-zA-Z]|[-]]+[\"]"); Matcher tempM = tempP.matcher(charSetStr); if (tempM.find()) { String charSet = charSetStr.substring(tempM.start(), tempM.end()); return charSet.substring(1, charSet.length() - 1); } } return null; } private void preparePaser() throws IOException { readSomeLine(defaultLineCount); Matcher m = charSetPattern.matcher(xmlContentBuffer); if (m.find()) { this.charSetTitle = this.xmlContentBuffer.substring(m.start(), m.end()); this.xmlContentBuffer.delete(0, m.end()); } m = elementPattern.matcher(xmlContentBuffer); if (m.find()) { this.rootElemetMark = this.xmlContentBuffer.substring(m.start(), m.end()); this.xmlContentBuffer.delete(0, m.end()); } m = elementPattern.matcher(xmlContentBuffer); if (m.find()) { this.childElementMark = this.xmlContentBuffer.substring(m.start(), m.end()); } this.xmlOutput = new XMLOutputBuffer(this.childElementMark); parserBuffer(); } private int readSomeLine(int lineCount) throws IOException { char buffer[] = new char[1024]; int i = 0; int index = 0; /* be careful of the sequence of the boolean caculation */ while (i++ < lineCount && (index = this.bufferedReader.read(buffer)) > 0) { xmlContentBuffer.append(buffer, 0, index); } return index; } private void parserBuffer() { int lastIndex = this.xmlContentBuffer.lastIndexOf(this.childElementMark); if (lastIndex > 0) { this.xmlOutput.append(this.xmlContentBuffer.substring(0, lastIndex)); this.xmlContentBuffer.delete(0, lastIndex); } } public StringBuffer popDividedDataAfterParser() throws IOException { while (this.xmlOutput.getItemCount() < defaultMaxOutputSize) { int i = readSomeLine(defaultLineCount); parserBuffer(); if (i < 0) break; } if (this.xmlOutput.getItemCount() == 0) return null; StringBuffer returnSB = this.xmlOutput.getXmlOutput(); this.xmlOutput.clearBuffer(); return returnSB.insert(0, this.rootElemetMark).append(this.rootElemetMark.replaceFirst("<", "</")); } public static void main(String args[]) throws Exception { String str = "F:/ringInfoXML/ringTime.xml"; XMLBufferTool xmlb = new XMLBufferTool(str); StringBuffer s = xmlb.popDividedDataAfterParser(); int i = 0; Matcher m = Pattern.compile("<ring>").matcher(s); while (m.find()) i++; System.out.println(i); System.out.println(s); } private static class XMLOutputBuffer { private StringBuffer xmlOutput; private int itemCount; private Pattern markPattern; XMLOutputBuffer(String markStr) { this.markPattern = Pattern.compile(markStr); xmlOutput = new StringBuffer(); itemCount = 0; } public void append(String str) { if (str == null || "".equals(str)) return; this.xmlOutput.append(str); Matcher m = this.markPattern.matcher(str); while (m.find()) this.itemCount++; } public void clearBuffer() { xmlOutput = new StringBuffer(); this.itemCount = 0; } public StringBuffer getXmlOutput() { return xmlOutput; } public int getItemCount() { return itemCount; } } } 代码中popDividedDataAfterParser() 输出的StringBuffer 可用来初始化一个 StringReader 再给dom4j 的saxReader去解析,这样联合一起用, 想处理多少,就先分出来解析多少,特别适合多线程的生产者和消费者的那种情况,希望对大家有用 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-07-10
SAX有event-based API,没有必要自己造轮子
|
|
返回顶楼 | |
发表时间:2008-07-10
引用 SAX有event-based API,没有必要自己造轮子 我接触xml的时间不是太长,我也希望能获得更多信息,我看了下您的建议,不知道这个event-based 是否是指的org.xml.sax.ContentHandler 接口中的那些 public void startDocument ()throws SAXException; public void startElement ( String namespaceURI, String localName, String qName, Attributes atts) throws SAXException; 。。。。。。。。。。 这些方法,如果是的话,那么这些handle中的方法,实现后在saxParser解析的时候是一直批量的解析下去,总不能解析到了一定数量的 Element 再停下来吧? 我当时也是觉得这样不灵活,用信号量使用wait()来停,我又觉得不是太优雅,所以就没用这个了 应该还是我知道的东西太少,希望楼上的大虾再指导下,最好有个简单的例子就更加万分感谢了! |
|
返回顶楼 | |
发表时间:2008-07-10
是的,SAX的event-based API就是你给出的那个接口,具体用法它的文档上就有
你说的不灵活,偶不明白你的具体需求,也就不好给建议了... |
|
返回顶楼 | |
发表时间:2008-07-10
我做的这个出现的需求可以是:
1。 我不需要把XML所有的数据解析完成后,再对数据做处理。 比如xml中有一万条数据(一条数据是一个子节点),我第一次只处理解析1-100的数据,并对数据做业务处理 , 下次再处理101-200的数据,再做业务处理 这样我就不用等全解析完后,再对所有解析后的数据做业务处理,也就是我要几条,就可以解析几条 2。一次性把一个xml 解析后,(假设xml 有几万条数据,那么在内存中就要有这么多的空间来存放)这样挺耗空间的,也不好做成buffer缓存的效果 |
|
返回顶楼 | |
发表时间:2008-07-10
sax的event处理是基于流操作的,不会在内存中构建整个文档树,可以满足你的第2点,但是它只相当于一个简单的iterator,并没有定位机制,你的第一点做不到,不过你可以自己弄一个计数器统计,不在这个计数范围内的就不要处理了,它解析速度是很快的,顶多就浪费一点点cpu资源
如果处理起来麻烦的话,就用StAX提供的定位机制,不过偶没有实际用过,你可以试试看 |
|
返回顶楼 | |
发表时间:2008-07-10
同样碰到过LZ的问题,70M的XML,一读服务器就OOM了
研究过sax,感觉很不好用,需要把已有的DOM结构的程序全部废掉重写。 目前采用的是用NIO内存映射方式读文件,然后把XML一段段摘取出来,分段解析处理, 速度还是很不错的,服务器也不OOM了。 |
|
返回顶楼 | |
发表时间:2008-07-10
看看xquery是不是基于流操作
|
|
返回顶楼 | |
发表时间:2008-07-11
kusix 写道 同样碰到过LZ的问题,70M的XML,一读服务器就OOM了
研究过sax,感觉很不好用,需要把已有的DOM结构的程序全部废掉重写。 目前采用的是用NIO内存映射方式读文件,然后把XML一段段摘取出来,分段解析处理, 速度还是很不错的,服务器也不OOM了。 如何一段段摘取出来的? |
|
返回顶楼 | |
发表时间:2008-07-11
引用 你可以自己弄一个计数器统计,不在这个计数范围内的就不要处理了,它解析速度是很快的,顶多就浪费一点点cpu资源 如果处理起来麻烦的话,就用StAX提供的定位机制,不过偶没有实际用过,你可以试试看 谢谢您回答, 的确那个第二个需求,的确是我主观思想在作怪了,认为既然经过所有的节点,就必然会把所有节点的数据读取处理并存在内存中,的确也是可以要多少处理多少,就看自己怎么利用现有的条件进行控制了 StAX提供的定位机制 还没碰过 谢谢您的提示 您说的那个计数器,我当时也有这样想,但是没去实践,也就是您说到的那点,以为每个点都看是否处理,怕浪费cpu,有空还是要实践下,这样才有更多的了解 在此谢谢各位的回复 这个是我发的第一个贴子,也是让人很开心的一个开始 |
|
返回顶楼 | |