编码问题估计是让每个程序员都烦恼过的问题。昨天又遇到一次用Dom4J解析XML文件一直报错的问题,检查了半天时间,才发现又是因为编码。其实代码本身很简单,网上搜了一圈,基本也都是这么写的,不知道为什么别人都没遇到这个问题,或许问题太简单了都不值得提吧。

       我们读XML的代码如下:

  1. BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8")); 
  2. reader = new SAXReader(); 
  3. doc=reader.read(br); 

        我们的文件是用UTF8保存的,但是有的可以正确保存,有的却不可以。出问题的数据就是有中文的地方,有意思的是不是所有中文都会出问题。把文件转成二进制的看了一下,文件本身没有什么异常。但执行程序报错如下:

  1. org.dom4j.DocumentException: Error on line 18 of document  : The element type "Title" must be terminated by the matching end-tag "</Title>". Nested exception: The element type "Title" must be terminated by the matching end-tag "</Title>". 
  2.     at org.dom4j.io.SAXReader.read(SAXReader.java:482) 
  3.     at org.dom4j.io.SAXReader.read(SAXReader.java:365) 

        初步定位就是因为编码造成了XML遇到特定字符解析出错。但是有一个值得注意的现象,就是在eclipse下运行是正确的,而且打包出来的在linux下也正确,而在windows下执行打包出来的程序则出错。看来和运行环境还有直接关系。

        这时有人发现在java运行命令中加上-Dfile.encoding=UTF8就正确了,但是所有的日志打印都成了乱码。看来很明显就是读程序的编码出问题,但是我们在输入流的时候明明已经指定了编码。我试了下Charset.defaultCharset()方法,果然linux下面默认是UTF8,而windows下面是gbk。然后我查了下dom4j的API,突然发现SAXReader还有getEncoding的方法,一调用果然是null。看来我们写的输入流指定编码没有生效,再查了下果然还有setEncoding方法,指定成UTF8以后问题解决。正确的代码如下:

  1. BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8")); 
  2. reader = new SAXReader(); 
  3. reader.setEncoding("UTF8"); 
  4. doc=reader.read(br); 

       这个问题确实比较诡异,dom4j的SAXReader居然没有直接使用已经读出来的内容,java内建字符集是unicode,应该就可以了,但他偏偏自己又做一次需要显示声明的转码。以后查问题还是要一步步缩小范围,然后定位出问题,再寻找解决办法。另外还是要多看源码,这次主要定位问题花的时间太多了。