2.1 字符编码和字符集
字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字,英文,标点符号,汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
- 字符编码(Character Encoding):就是一套自然语言的字符与二进制数之间的对应规则。
字符集
- 字符集(Charset):也叫编码表,是一个系统支持的所有字符集的集合,包括各国家文字,标点符号,图形符号,数字。
计算机要准确的存储和识别各种字符集符号,需要进行字符编码,常见的字符集有ASCII字符集,GBK字符集,Unicode字符集等。
可见,当指定了编码,它对应的字符集就自然指定了,所以编码才是我们最需要关心的。
- ASCII字符集:美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符和可显示字符。基本的ASCII字符集,使用的是7位(bits)表示一个字符,共128个字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
- ISO-8859-1字符集:拉丁码表,用于显示欧洲使用的语言,使用单字节编码,兼容ASCII编码。
- GBXXX字符集:GB就是国标的意思,是为了显示中文而设计的一套字符集。GBK:最常用的中文编码表,使用了双字节的编码方案。
- Unicode字符集:Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为万国码。它最多使用4个字节来表达每个字母,符号,或者文字。有三种编码方案,UTF-8,UTF-16,UTF-32,最为常用的就是UTF-8编码。
UTF-8编码,可以用来表示Unicode标准中的任何字符,它是电子邮件,网页及其他存储或传送文字的应用中优先采用的编码。互联网工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码,它使用一到四个字节为每个字符编码,编码规则:
- 128个US-ASCII字符,只需要一个字节编码
- 拉丁等字符了,需要两个编码
- 大部分常用字,含中文,使用三个字节编码
- 其他极少使用的Unicode辅助字符,使用四字节编码。
2.2 编码引出的问题
在IDEA中,使用FileReader读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是当读取Windows系统中创建的文本文件的时候,由于Windows系统默认的是GBK编码,就会出现乱码。
private static void show1() {
try (FileReader fileReader = new FileReader("E:\\01-尚硅谷MySQL核心技术-婷姐\\资料、代码\\note\\备注.txt");
) {
int read;
while ((read = fileReader.read()) != -1) {
System.out.println((char) read);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
那么如何读取GBK编码的文件呢?
2.3 InputStreamReader类
转换流 java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台默认字符集。
构造方法
- InputStreamReader(InputStream in):创建一个使用默认字符集的字符流
- InputStreamReader(InputStream in,String charsetName):创建一个指定字符集的字符流
构造举例,代码如下:
- InputStreamReader isr1=new InputStreamReader(new FileInputStream("in.txt"));
- InputStreamReader isr2=new InputStreamReader(new FileInputStream("in.txt"),"GBK");
private static void show2() {
//定义文件路径,文件为GBK编码
String FileName = "E:\\01-尚硅谷MySQL核心技术-婷姐\\资料、代码\\note\\备注.txt";
//创建流对象,默认为UTF8编码
try (InputStreamReader isr1 = new InputStreamReader(new FileInputStream(FileName));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName),"GBK");
) {
//定义变量,保存字符
int read;
//使用默认的编码字符流读取,乱码
while ((read = isr1.read()) != -1) {
System.out.print((char) read);
}
System.out.println();
//使用指定编码的字符流读取,正常解析
while ((read = isr2.read()) != -1) {
System.out.print((char) read);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
2.4 OutputStreamWriter类
转换流 java.io.OutputStreamWriter,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
- OutputStreamWriter(OutputStream in):创建一个使用默认字符集的字符流。
- OutputStreamWriter(OutputStream in,String charsetName): 创建一个指定的字符集的字符流
构造举例,代码如下:
- OutputStreamWriter isr1=new OutputStreamWriter(new FileOutputstream("out.txt"));
- OutputStreamWriter isr2=new OutputStreamWriter(new FileOutputStream("out.txt"),"GBK");
private static void show3() {
//定义文件路径
String FileName = "E:\\01-尚硅谷MySQL核心技术-婷姐\\资料、代码\\note\\备注.txt";
//创建流对象,默认UTF8编码
try (OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream(FileName, true));
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName, true), "GBK");
) {
//写出数据
// osw1.write("你好");
osw2.write("你好");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
2.5 练习:转换文件编码
将GBK编码的文件,转换为UTF-8编码的文本文件。
案例分析
- 指定GBK编码的转换流,读取文本文件
- 使用UTF-8编码的转换流,写出文本文件
private static void show4() {
//定义文件路径
String srcFile = "E:\\01-尚硅谷MySQL核心技术-婷姐\\资料、代码\\note\\备注.txt";
String desFile = "a.txt";
//创建流对象
//转换输入流,指定GBK编码
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(desFile), "UTF-8")
) {
//读写数据,定义数组
char[] cbuf = new char[1024];
//定义长度
int len;
//循环读取
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf, 0, len);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}