字符编码和字符集
字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
编码:字符 --> 字节
解码:字节 --> 字符
- 字符编码,是一套自然语言的字符与二进制数之间的对应规则。
字符集
- 字符集,也叫编码表,是一个系统支持的所有字符集合,包括国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识別各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
编码引出的问题
在IDEA中,使用FileReader读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取系统中创建的文本文件时,由于系统的默认是GBK编码,就会出现乱码。
那么该如何解决呢?我们可以使用InputStreamReader类、OutputStreamWriter类,指定编码来进行读写操作,这时候就不会出现乱码的情况了。
OutputStreamWriter类
java.io.OutputStreamWriter是字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节(编码)。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
OutputStreamWriter类是java.io.Writer的子类,所以可以使用父类方法:
public void write(int c) // 写入单个字符。 public void write(char cbuf[]) // 写入字符数组。 abstract public void write(char cbuf[], int off, int len) // 写入字符数组的某一部分,off是数组的开始索引,len是写的字符个数。 public void write(String str) // 写入字符串。 public void write(String str, int off, int len) //写入字符的某一部分。off是字符的开始素,len是写的字符个数。 abstract public void flush() // 刷新该流的缓冲。 abstract public void close() // 关闭此流,但会先刷新它。
构造方法
OutputStreamWriter(OutputStream out) // 创建使用默认编码的OutputStreamWriter对象 OutputStreamWriter(OutputStream out, String charsetName) // 创建使用指定编码的OutputStreamWriter对象
参数:
OutputStreamWriter out:字节输出流
String charsetName:指定编码表的名称,不区分大小写。如utf-8/UTF-8。
使用步骤:
1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的編码表名称。 2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储到缓冲区中(编码)。 3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)。 4.释放资源。
举例:指定编码,将数据保存到文件中。
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class DemoOutputStreamWriter { public static void main(String[] args) throws IOException { Gbk_TXT(); } private static void Gbk_TXT() throws IOException { // 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的編码表名称。指定编码为GBK。 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/OutputStreamWriter.txt"), "gbk"); // 使用OutputStreamWriter对象中的方法write,把字符转换为字节存储到缓冲区中(编码)。 for (int i = 0; i < 5; i++) { osw.write("你好!" + i); osw.write(" "); } // 使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)。 osw.flush(); // 释放资源。 osw.close(); } }
运行,生成一个OutputStreamWriter.txt文件,文件内容如下:
由于IDEA默认编码是UTF-8,这里使用了GBK编码格式写入数据进文件,所以在IDEA里面查看文件的内容出现乱码。
InputStreamReader类
java.io.InputStreamReader是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符(解码)。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
InputStreamReader类是java.io.Reader的子类,所以可以使用父类方法:
public void close() // 关闭此流并释放与此流相关联的任何系统资源。 public int read() // 从输入流读取一个字符。 public int read(char[] chars) // 从输入流中读取一些字符,并将它们存储到字符数组chars中。
构造方法
InputStreamReader(InputStream in) // 创建默认字符集的InputStreamReader对象 InputStreamReader(InputStream in, String charsetName) // 创建指定字符集的InputStreamReader对象
参数:
InputStream in:字符输入流
String charsetName:指定编码表的名称,不区分大小写。如gbk/GBK。
使用步骤:
1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称。 2.使用InputStreamReader对象中的方法read,读取文件。 3.释放资源。
注意事项:构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码。
举例:按指定解码格式,读取OutputStreamWriter.txt文件的内容
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class DemoInputStreamReader { public static void main(String[] args) throws IOException { decode_GBK(); } private static void decode_GBK() throws IOException { // 创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称。 InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/OutputStreamWriter.txt"), "GBK"); // 使用InputStreamReader对象中的方法read,读取文件。 char[] chars = new char[25]; while ((isr.read(chars)) != -1) { System.out.println(chars); } // 释放资源。 isr.close(); } }
控制台输出:
你好!0 你好!1 你好!2 你好!3 你好!4
练习:转换文件编码
将编码GBK编码的文件文本,转换为UTF-8编码的文件文本。
分析:
1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK。 2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8。 3.使用InputStreamReader对象中的方法read,读取文件。 4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中。 5.释放资源。
GBK.txt文件内容如下:
代码实现:
import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; public class DemoInOutAndReaderWriter { public static void main(String[] args) throws IOException { method(); } private static void method() throws IOException { // 创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK。 InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/GBK.txt"), "GBK"); // 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8。 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/UTF_8.txt"), "UTF-8"); // 使用InputStreamReader对象中的方法read,读取文件。 int len = 0; while ((len = isr.read()) != -1) { osw.write(len); } // 释放资源。 isr.close(); osw.close(); } }
运行生成一个UTF_8.txt文件,文件内容如下: