编码问题估计是让每个程序员都烦恼过的问题。昨天又遇到一次用Dom4J解析XML文件一直报错的问题,检查了半天时间,才发现又是因为编码。其实代码本身很简单,网上搜了一圈,基本也都是这么写的,不知道为什么别人都没遇到这个问题,或许问题太简单了都不值得提吧。
我们读XML的代码如下:
- BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
- reader = new SAXReader();
- doc=reader.read(br);
我们的文件是用UTF8保存的,但是有的可以正确保存,有的却不可以。出问题的数据就是有中文的地方,有意思的是不是所有中文都会出问题。把文件转成二进制的看了一下,文件本身没有什么异常。但执行程序报错如下:
- 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>".
- at org.dom4j.io.SAXReader.read(SAXReader.java:482)
- 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以后问题解决。正确的代码如下:
- BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
- reader = new SAXReader();
- reader.setEncoding("UTF8");
- doc=reader.read(br);
这个问题确实比较诡异,dom4j的SAXReader居然没有直接使用已经读出来的内容,java内建字符集是unicode,应该就可以了,但他偏偏自己又做一次需要显示声明的转码。以后查问题还是要一步步缩小范围,然后定位出问题,再寻找解决办法。另外还是要多看源码,这次主要定位问题花的时间太多了。
转载于:https://blog.51cto.com/passover/477310