字节和字符的转换是要通过转换流:InputStreamReader和OutputStreamWriter。这两个流对象时加入了编码表的流对象,当然加入编码表的流对象还有PrintStream和PrintWriter,但是这两个对象只能进行数据的打印,不能读取。
二,所谓的编码表就是,机器中二进制编码对应的字符,比如ASCII,用低七位的二进制位表示他们的字符;通常中文操作系统默认的是GBK编码。早期美国最先出来的是ASCII码表,是采用低七位表示。后来欧洲
拉丁语采用八位表示自己的字符,是在七位的基础上添加了一位1,添加后也就是负数的二进制表示,避免了重复;
后来中国也采用这种二进制对应自己的字符做出了自己的编码表,也就是GB2312和后来的GBK(在原来基础上添加了更多的汉字),由于中文比较复杂,就采用两个字节表示一个汉字,也就是16位的二进制数的排列组合。
后来国际上为了统一编码表,做了一个Unicode编码表,表示多种文字,都是用两个字节来表示,Java中就是用的这种编码。最多用3个字节表示一个文字。
三,常见的编码表
ASCII:美国标准信息交换码(用一个字节的7位表示)
ISO8859-1:拉丁码表。欧洲码表。(用一个字节的8位表示)
GB2312:中国中文编码表
GBK:中国中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字.。(所有文字都是使用两个字节表示,java语言使用的就是该码表)
UTF-8:最多用三个字节表示一个文字。
如果在编程过程中用UTF-8编码表写的字符文件,在读取的时候查的是GBK编码表则会出现别的汉字,但不是我们想要的结果。
如果编程中指定的是GBK,在读取的时候不小心指定了UTF-8则会出现问号,原因是GBK编码的汉字是两个字符,读取时查找UTF-8编码表,会三个字节三个字节一读取,可能会查不到,所以会显示出问号。
需求:输出流使用UTF-8编码向文件中写入数据,使用不同的编码读取文件中的数据观察结果。
InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
import java.io.*;
public class UnicodeDemo
{
public static void main(String[] args) throws IOException {
//writeDe();
readDe();
}
public static void readDe() throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("UTF-8.txt"),"UTF-8");
//这里不指定编码参数,说明是已默认的GBK编码来读取UTF-8文件的,但是由于UTF-8.txt是用UFT-8编码
//写出来的,你好是六个字节,所以会以两个字节两个字节的方法到GBK码表中查找是什么字符,,所以出来
//的不是我们想要的结果。但是如果指定用UTF-8编码表查找的话就会显示出你好。
char[] b = new char[10];
int len = 0;
len = isr.read(b);
System.out.println(new String(b,0,len));
isr.close();
}
public static void writeDe() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"UTF-8");
//如果不规定字符编码,则默认的是GBK;
osw.write("你好");
osw.close();
}
}
四,编码与解码
编码:字符转换成字节; <比如将文本存储到硬盘中就属于编码>
解码:字节转换成字符; <比如将硬盘中的存储的文本文件用记事本打开>
String --> byte[] str.getBytes()
byte[] --> String new String(byte[])
在编码时,如果第一编码用的是GBK但是解码查的是ISO8859-1,那么应该怎么处理呢?
因为在编码的时候用的是GBK编码表编码的,传送到接收方时的是一组数字;而接收方查的是ISO8859-1的表,就会出现乱码,但是因为ISO8859-1的编码表也是两个字节表示一位,所以可以再次用ISO8859-1的表编码一次,这时候返回的还是之前用GBK编码的那一组数字,最后再用GBK解码一次就可以完成。
注意:如果在编码时,出现错误,那么解码一定是不能得到想要的结果。但是如果编码正确,解码时出现错误,可以解码后在使用解码时的编码表编码一次,然后在使用正确的编码表解码是可以得到正确结果的。但是这种情况只是使用与GBK和ISO8859-1之间(我们能涉及到的码表有GBK,UTF-8,ISO8859-1三种),如果使用GBK编码,解码时误用了UTF-8,使用上述方法则行不通,因为UTF-8和GBK都识别中文造成的。Tomcat服务器使用的是ISO8859-1编码,ISO8859-1不识别中文,所以可以。过程如下:
import java.util.*;
public class EncodeDemo
{
public static void main(String[] args) throws Exception {
String s1 = "你好";
byte[] by = s1.getBytes("GBK");//使用GBK编码
System.out.println(Arrays.toString(by));
//解码:
String s2 = new String(by,"ISO8859-1");//使用ISO8859-1解码
System.out.println(s2);
//在次编码:
byte[] by2 = s2.getBytes("ISO8859-1");
System.out.println(Arrays.toString(by2));
//再次解码:
String s3 = new String(by,"GBK");
System.out.println(s3);
}
}