`
sharong
  • 浏览: 492349 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
D1667ae2-8cfc-3b68-ac7c-5e282789fa4a
论开源
浏览量:8695
7eb53364-fe48-371c-9623-887640be0185
Spring-data-j...
浏览量:13025
社区版块
存档分类
最新评论

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

阅读更多
近日在开发爬虫程序时发现,如果事先不指定正确的字符集编码,在得到InputStream字节流实例后使用程序自身去判断,相关代码如下:
if(charset == null || "".equals(charset)) {
	reader = new InputStreamReader(inputStream);
	charset = reader.getEncoding();
}else {
	reader = new InputStreamReader(inputStream, charset);
}		

在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,然后接着逐行读取。代码如下:
//原始的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;
			}
		}				
	}
}

这种方法可以得到正确的编码格式的page页面,然而由于使用不同的字符集实例化InputStreamReader,造成inputStream流在使用新的字符集重新实例化后,之前的定位发生变化,前后的位置不一致,中间往往会漏掉大约400多行字符。
研究了一些相关开源项目,例如HtmlParser,发现也是无法提供一个正确的,好用的方法来判断字节流的编码格式。
分享到:
评论
3 楼 rain2005 2010-07-05  
难道不能直接获取http响应编码吗?
2 楼 sharong 2010-07-04  
我的方法不就是边下载字节流,边转换为字符流进行读取。请问怎样全部下载下来,然后再去判断?难道不需要转化为字符流么?
1 楼 beneo 2010-06-02  
sharong 写道
近日在开发爬虫程序时发现,如果事先不指定正确的字符集编码,在得到InputStream字节流实例后使用程序自身去判断,相关代码如下:
if(charset == null || "".equals(charset)) {
	reader = new InputStreamReader(inputStream);
	charset = reader.getEncoding();
}else {
	reader = new InputStreamReader(inputStream, charset);
}		

在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,然后接着逐行读取。代码如下:
//原始的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;
			}
		}				
	}
}

这种方法可以得到正确的编码格式的page页面,然而由于使用不同的字符集实例化InputStreamReader,造成inputStream流在使用新的字符集重新实例化后,之前的定位发生变化,前后的位置不一致,中间往往会漏掉大约400多行字符。
研究了一些相关开源项目,例如HtmlParser,发现也是无法提供一个正确的,好用的方法来判断字节流的编码格式。


1. 难道不能够先把inputStream下载下来,然后再自己去判断字符,再去转化么?不明白为什么要下载2次

2. available 是一个估计值,你可以用获得的byte[]长度作为av

相关推荐

    判断字符编码格式代码

    给定的代码片段展示了如何使用C++来判断输入字符串的字符编码格式。代码中主要考虑了以下几种情况: #### 1. BOM(Byte Order Mark)检测 BOM是一种特殊的字符序列,通常出现在文件的开头,用来标识文件的编码格式...

    Java判断文件的编码

    ### Java判断文件编码的方法 在Java开发中,经常会遇到需要处理不同编码格式的文件的情况。为了确保程序能够正确解析文件内容,必须先判断文件的编码格式。本文将详细介绍如何使用Java来判断文件是否为UTF-8或GBK...

    Java字符集和编码

    为了处理不同编码格式的数据,Java提供了一系列的字符流和字节流类,如`InputStreamReader`和`OutputStreamWriter`等,它们可以将字节流转换为字符流,从而实现对各种编码格式的支持。 在实际开发中,理解字符集和...

    java字符编码监听器

    Java字符编码监听器是Java Web开发中的一个重要概念,主要用于处理HTTP请求和响应中的字符编码问题。在Java Servlet规范中,提供了`SetCharacterEncodingFilter`这样的过滤器,用于确保请求参数和响应内容的正确编码...

    java 输入输出流

    字符流通常比字节流更适合处理文本数据,因为它们能自动处理字符编码。 3. **缓冲流**:为了提高性能,Java提供了缓冲流,如`BufferedReader`和`BufferedWriter`,它们在底层字节或字符流之上添加了一个缓冲区,...

    Java IO 字节流 字符流

    Java IO系统分为两大类:字节流和字符流。字节流主要用于处理任何类型的原始数据,如图片、音频文件或者二进制文件,而字符流则专注于处理基于文本的数据。本文将深入探讨这两类流的原理、用途以及它们之间的关联。 ...

    JAVA中文字符编码问题详解.doc

    1. 按指定的字符编码形式,从源输入流中读取字符数据 2. 以 UNICODE 编码形式将字符数据存储在内存中 3. 按指定的字符编码形式,将字符数据编码并写入目的输出流中 因此,JAVA 处理字符时总是经过了两次编码转换,...

    Java 正则表达式判断字符串是否包含中文

    ### Java正则表达式判断字符串是否包含中文 在日常的软件开发过程中,我们经常会遇到需要对输入的字符串进行校验的情况。例如,在处理用户输入、文本分析或数据清洗时,可能需要判断一个字符串中是否包含中文字符。...

    字符串长度的判断 JAVA

    在Java编程语言中,字符...理解字符串的长度判断和截取是Java编程的基础,它们在实际编程中有着广泛的应用,例如在输入验证、数据处理、格式化输出等场景。熟练掌握这些基本操作,将有助于编写出更加高效和可靠的代码。

    java 判断汉字 汉字的判断

    ### Java判断字符串是否包含汉字的方法 在开发过程中,有时我们需要判断一个字符串是否包含汉字,并根据判断的结果执行不同的逻辑。这通常出现在需要处理多语言输入的情况下,例如用户输入验证、文本分析等场景。...

    JAVA 字符流与字节流

    在Java编程语言中,输入/输出(I/O)操作是处理数据流的关键部分,而字符流与字节流则是实现这些操作的两种基本方式。理解它们的区别和应用场景对于任何Java开发者来说都是至关重要的。 ### 字节流 字节流是最基本...

    java代码笔记2010-06-12:java控制台输入各类型类实现;以及判断输入字符串里面是否有数字的两种方法:方法1:转换成字符数组;方法2:正则表达式。

    首先,Java通过`System.in`流提供对控制台输入的访问。我们可以使用`Scanner`类来读取用户输入。以下是一个基本示例,用于获取用户输入的整数: ```java import java.util.Scanner; public class ConsoleInput { ...

    实验9 Java输入输出流.doc

    Java的I/O系统主要分为两大类:字节流(Byte Stream)和字符流(Character Stream)。字节流处理的是8位的字节数据,适用于处理任何类型的数据,包括图像、音频等二进制文件;而字符流则处理16位的Unicode字符,适合...

    通过对字符的unicode编码进行判断来确定字符是否为中文

    ### 通过对字符的Unicode编码进行判断来确定字符是否为中文 在计算机编程中,经常需要对文本中的字符进行处理和判断。例如,在处理用户输入或分析文档时,可能需要识别哪些字符是中文字符。本篇文章将详细介绍如何...

    java字节流和字符流

    Java中的字节流和字符流是IO操作中的两种基本类型,它们主要用于数据的输入和输出。字节流处理的数据单位是字节,而字符流处理的是Unicode字符。 字节流: 字节流主要由两个核心类构成:`InputStream`和`...

    Java字符编码简介_动力节点Java学院整理

    Java提供了诸如`InputStreamReader`、`OutputStreamWriter`、`FileReader`、`FileWriter`等类来处理不同编码的输入输出流,确保数据的准确无误。此外,理解和掌握Java的`Charset`类以及相关API对于处理编码问题至关...

    JAVA IO流缓冲字节流缓冲字符流等流经典代码示例加注释总结.rar

    2、常用21个IO流:FileWriter、FileReader、...3、JAVA IO流经典代码示例,示例从易到难。代码功能涉及字节、字符、字符串、文本文件、图片、音频、视频。演示错误用法和经典用法。 4、代码的结构可查看README文件。

    JAVa输入输出流程序

    Java IO流体系基于一种层次结构,分为字节流和字符流两大类。字节流处理的是8位的字节,包括InputStream和OutputStream两个基类,分别代表所有输入流和输出流的父类。字符流处理的是16位的Unicode字符,由Reader和...

    java字符编码解析.zip

    2. **输入输出流**:Java的`InputStreamReader`和`OutputStreamWriter`用于处理字符流,需要指定对应的编码。例如,读取GBK编码的文件时,应使用`new InputStreamReader(fileInputStream, "GBK")`。 3. **网络传输*...

    java字符编码转换详细过程

    如果程序需要接收用户输入,输入的字符串会按照默认的`file.encoding`编码进行编码和转换。 - **EJB类和其他不可直接运行的支持类**:这些类通常不会直接与用户交互,而是作为服务端组件或者被其他程序调用。 - *...

Global site tag (gtag.js) - Google Analytics