JAVA判断输入流字符编码的困惑

近日在开发爬虫程序时发现,如果事先不指定正确的字符集编码,在得到InputStream字节流实例后使用程序自身去判断,相关代码如下:
[code]
if(charset == null || "".equals(charset)) {
reader = new InputStreamReader(inputStream);
charset = reader.getEncoding();
}else {
reader = new InputStreamReader(inputStream, charset);
}
[/code]
在if块语句中,往往会得到错误的charset,原因是创建了一个使用系统平台字符集的 InputStreamReader实例,同时很多专业网站在制作时使用了一个小技巧,就是在文件开头敲空格等,这样就会造成JDK的相关类在判断抓取到的输入流是什么编码出现错误,继而抓取下来的都是包含乱码的网页。例如抓取http://www.chinahr.com首页代码,根据if中的程序判断,charset=”UTF8”,而页面实际设置了charset=”gb2312”。从这里也可看出JDK在底层的字节流,字符流的实现上仍然是不够成熟,容易出现错误。
因为在构成InputStreamReader实例时的字符集出错,所以即使对抓取到的乱码的网页字符串重新转码也得不到正确的结果。
由于inputStream字节流只允许读取一遍,往往还不支持mark(int),reset()等方法,所以根据这个特性,思考了若干解决方案,其中比较接近的一个是,先使用缺省字符集将字节流inputStream转换为字符流InputStreamReader,再使用BufferedReader类包装一层,在BufferedReader读取到包含charset的时候,对charset进行判断后,重新实例化InputStreamReader,然后接着逐行读取。代码如下:
[code]
//原始的BufferedReader实例,reader即为上面代码产生的实例
bufferedReader = new BufferedReader(reader);
boolean mark = false;

StringBuffer buffer = new StringBuffer();
String str = "";
int count = 0;
while ((str = bufferedReader.readLine()) != null) {
if(mark && count > 0) {
bufferedReader.reset();
count = 0;
}

buffer.append(str).append("\n");

if(!mark){
count ++;
String tempStr = str.toLowerCase();
if(tempStr.indexOf(DetectorConstants.HtmlTagProperty.HTTP_EQUIV) != -1
&& tempStr.indexOf(DetectorConstants.HtmlTagProperty.CHARSET) != -1){
//此处略过了实际分析过程,直接给出结果
String anotherCharset = "gb2312";
if(anotherCharset != null && !"".equals(anotherCharset) && !anotherCharset.equals(charset)){
charset = anotherCharset;
reader = new InputStreamReader(urlStream, anotherCharset);
bufferedReader = new BufferedReader(reader);

int av = urlStream.available();
bufferedReader.mark(av + 1);//也可以使用count试试
mark = true;
}
}
}
}
[/code]
这种方法可以得到正确的编码格式的page页面,然而由于使用不同的字符集实例化InputStreamReader,造成inputStream流在使用新的字符集重新实例化后,之前的定位发生变化,前后的位置不一致,中间往往会漏掉大约400多行字符。
研究了一些相关开源项目,例如HtmlParser,发现也是无法提供一个正确的,好用的方法来判断字节流的编码格式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值