近日在开发爬虫程序时发现,如果事先不指定正确的字符集编码,在得到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,发现也是无法提供一个正确的,好用的方法来判断字节流的编码格式。
分享到:
相关推荐
运用io流完美解决:字符编码问题。
此外,处理多国语言和多编码环境时,需要确保整个数据流(输入、处理、输出)保持一致的编码规则,以避免乱码问题。 总之,理解并掌握Java中的字符集编码,不仅有助于编写出兼容性更强的代码,也是提升软件质量的...
Java IO系统分为两大类:字节流和字符流。字节流主要用于处理任何类型的原始数据,如图片、音频文件或者二进制文件,而字符流则专注于处理基于文本的数据。本文将深入探讨这两类流的原理、用途以及它们之间的关联。 ...
JAVA及相关字符集编码问题 在深入探讨JAVA与字符集编码问题之前,我们首先需要理解不同字符集编码的基本概念以及它们在JAVA环境中的应用。字符集编码是计算机系统中表示文字的一种方式,它决定了如何将字符转换为二...
1. 按指定的字符编码形式,从源输入流中读取字符数据 2. 以 UNICODE 编码形式将字符数据存储在内存中 3. 按指定的字符编码形式,将字符数据编码并写入目的输出流中 因此,JAVA 处理字符时总是经过了两次编码转换,...
### Java判断字符串是否包含汉字的方法 在开发过程中,有时我们需要判断一个字符串是否包含汉字,并根据判断的结果执行不同的逻辑。这通常出现在需要处理多语言输入的情况下,例如用户输入验证、文本分析等场景。...
在Java编程语言中,字符...理解字符串的长度判断和截取是Java编程的基础,它们在实际编程中有着广泛的应用,例如在输入验证、数据处理、格式化输出等场景。熟练掌握这些基本操作,将有助于编写出更加高效和可靠的代码。
- `InputStreamReader` 和 `OutputStreamWriter`:它们可以与`InputStream`和`OutputStream`结合使用,用于在字节流和字符流之间进行编码转换。 - `BufferedReader` 和 `BufferedWriter`:提供缓冲功能,提高读写...
- Java中的`InputStreamReader`和`OutputStreamWriter`用于在字节流和字符流之间转换,可以指定字符编码。 - URL编码:URL中非ASCII字符需要使用`URLEncoder.encode()`进行编码,`URLDecoder.decode()`解码。 3. ...
Java的I/O系统主要分为两大类:字节流(Byte Stream)和字符流(Character Stream)。字节流处理的是8位的字节数据,适用于处理任何类型的数据,包括图像、音频等二进制文件;而字符流则处理16位的Unicode字符,适合...
Java中的字节流和字符流是IO操作中的两种基本类型,它们主要用于数据的输入和输出。字节流处理的数据单位是字节,而字符流处理的是Unicode字符。 字节流: 字节流主要由两个核心类构成:`InputStream`和`...
Java的输入输出流分为字节流和字符流两大类,每类又分别有输入流和输出流四种类型,即InputStream、OutputStream、Reader和Writer。下面我们将深入探讨这些概念,并通过一个简单的例子来说明其使用方法。 字节流...
2. **InputStreamReader和OutputStreamWriter**:这两个类是Java I/O流中的重要组成部分,它们分别用于将字节流转换为字符流和将字符流转换为字节流。在处理不同编码时,我们可以指定所需的编码类型,如`new ...
java 输入输出流加密源码 里面详细介绍了加密流的代码,是文件的输入输出流,不过大同小异 其他io一样
java判断一段话中是否有电话号码,并将其进行隐藏
2、常用21个IO流:FileWriter、FileReader、...3、JAVA IO流经典代码示例,示例从易到难。代码功能涉及字节、字符、字符串、文本文件、图片、音频、视频。演示错误用法和经典用法。 4、代码的结构可查看README文件。
最好在myeclipse里面运行,可以直接在下面输入一段字符串,运行便可以看出结果。
### JAVA中汉字字符转化为英文字符 #### 知识点概览 本文将详细介绍如何在Java中实现汉字到英文字符的转换。此技术主要用于提取汉字的首字母或进行其他基于字符编码的操作。通过以下两个核心方法:`toTureAsciiStr`...
- `InputStreamReader` 和 `OutputStreamWriter` 可以将字节流转换为字符流,它们接受一个字节流作为参数并指定字符编码。 以上就是Java输入输出流的基本概念和常见写法。在实际应用中,根据需求选择合适的流类型...