当使用不同的编码方式读取或者写入文件时,就会出现乱码问题,来看示例:
public class Main {
public static void main(String[] args) {
String s = "大帅比!";
try {
// 将字符串按GBK编码方式保存到文件中
OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream("fos.txt"), "GBK");
out.write(s);
out.close();
FileReader fileReader = new FileReader("fos.txt");
int read;
while ((read = fileReader.read()) != -1) {
System.out.print((char)read);
}
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上面的示例代码中,首先定义了一个包含中文字符的字符串,然后将该字符串按 GBK 编码方式保存到文件中,接着将文件按IDEA中默认的编码方式(UTF-8)读取,并显示内容。此时就会出现乱码问题,显示为“��Ĭ������”。
这是因为文件中的 GBK 编码的字符在使用 UTF-8 解码时无法正确解析,从而导致出现乱码问题。
那如何才能解决乱码问题呢?
这就引出我们今天的主角了——转换流。
在java中,转化流(Transformation Stream)在读取和写入文本数据时可以指定编码方式。
转换流主要有两类:InputStreamReader和OutputStreamWriter。这两个类都属于字符流。其中InputStreamReader将字节输入流转为字符输入流,继承自Reader。OutputStreamWriter是将字符输出流转为字节输出流,继承自Writer。
可以指定编码和解码的方式。
构造方法:
- InputStreamReader(InputStream in):创建一个使用默认字符编码的InputStream,从指定的InputStream读取数据。
- InputStreamReader(InputStream in, String charsetName):创建一个指定字符集的字符流。
代码:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
但是在JDK11之后进行了优化,在FileReader和FileWriter中增加了一个构造,可以指定字符编码方式。
练习1:将GBK编码的文件转换为UTF-8编码的。
Unicode字符集中字符的码点如何转换为GBK进行存储?
使用read方法读取出来的返回值不是GBK字符集中对应的码点吗?为何能直接按UTF-8编码方式写入?并且还是原来的字符?
public class IO12 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("bbb//gbkfile.txt", Charset.forName("GBK"));
FileWriter fw = new FileWriter("bbb//utf-8file.txt", Charset.forName("UTF-8"));
int b;
while ((b = fr.read()) != -1) {
fw.write(b);
}
fw.close();
fr.close();
}
}
练习2:利用字节流读取文件中的数据,要求每次读取一整行且不能出现乱码。
首先字节流不能用来读取中文,肯定是会乱码的,所以要转换为字符流,又要求每次读取一整行数据,这是缓冲字符流的特有方法,所以又需要再转换为缓冲字符流。
public class IO13 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("bbb//csb.txt")));
String str;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
}
}
两个问题:
(1)转换流的名称是什么?
(2)转换流的作用?
①指定编码和解码的方式;
②字节流想要使用字符流中的方法。