为什么要有转换流?
在IDEA中,使用 FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的 UTF-8 编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。为了解决这个问题的出现Java中出现了转换流,我们可以指定转换流的编码/解码方式来解决乱码问题。
OutputStreamWriter类
转换流 java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。继续自父类的共性成员方法:
- void write(int c) 写入单个字符。
- void write(char[] cbuf)写入字符数组。
- abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
- void write(String str)写入字符串。
- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- void flush()刷新该流的缓冲。
- void close() 关闭此流,但要先刷新它。
构造方法:
- OutputStreamWriter(OutputStream out)创建使用默认字符编码的 OutputStreamWriter。
- OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。
构造方法参数:
- OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
- String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,...不指定默认使用UTF-8
使用步骤:
- 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
- 使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
- 使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
- 释放资源
代码演示
package demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo01OutputStreamWriter { public static void main(String[] args) throws IOException { //1创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称,不指定就是UTF-8格式的 //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day21\\UTF文件.txt")); /* 使用转换流OutputStreamWriter写GBK格式的文件 */ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day21\\GBK文件.txt"), "GBK"); //2使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码) osw.write("榨汁机是个好东西"); //3使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程) osw.flush(); //释放资源 osw.close(); } }
InputStreamReader类
转换流 java.io.InputStreamReader ,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。继承自父类的共性成员方法:
- int read() 读取单个字符并返回。
- int read(char[] cbuf)一次读取多个字符,将字符读入数组。
- void close() 关闭该流并释放与之关联的所有资源。
构造方法:
- InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
- InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。
构造方法参数:
- InputStream in:字节输入流,用来读取文件中保存的字节
- String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,...不指定默认使用UTF-8
使用步骤:
- 创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
- 使用InputStreamReader对象中的方法read读取文件
- 释放资源
注意事项:
- 构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
代码演示
package demo02; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo01InputStreamReader { public static void main(String[] args) throws IOException { //创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称,不指定默认使用UTF-8 //InputStreamReader isr = new InputStreamReader(new FileInputStream("day21\\UTF文件.txt")); /* 使用InputStreamReader读取GBK格式的文件 */ InputStreamReader isr = new InputStreamReader(new FileInputStream("day21\\GBK文件.txt"), "GBK"); //使用InputStreamReader对象中的方法read读取文件 int len = 0; char[] b = new char[1024]; while ((len = isr.read(b)) != -1) { System.out.println(new String(b, 0, len)); } //3.释放资源 isr.close(); } }
练习:转换文件编码
将GBK编码的文本文件,转换为UTF-8编码的文本文件。
import java.io.*; /* 分析: 1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK 2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8 3.使用InputStreamReader对象中的方法read读取文件 4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中 5.释放资源 */ public class Demo04Test { public static void main(String[] args) throws IOException { //1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK InputStreamReader isr = new InputStreamReader(new FileInputStream("我是GBK格式的文本.txt"),"GBK"); //2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("我是utf_8格式的文件.txt"),"UTF-8"); //3.使用InputStreamReader对象中的方法read读取文件 int len = 0; while((len = isr.read())!=-1){ //4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中 osw.write(len); } //5.释放资源 osw.close(); isr.close(); } }