1 编码表
1.1 思考:
- 既然字节流可以操作所有文件,那么为什么还要学习字符流 ?
- 如果使用字节流 , 把文本文件中的内容读取到内存时, 可能会出现乱码
- 如果使用字节流 , 把中文写入文本文件中 , 也有可能会出现乱码
1.2 编码表介绍
- 计算机中储存的信息都是用二进制数据表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
- 按照编码表规则,将字符存储到计算机中,称为编码。
- 按照同样的编码表规则,将存储在计算机中的二进制数据解析显示出来,称为解码 。
- 编码和解码使用的码表必须一致,否则会导致乱码。
- 简单理解:
- 存储一个字符a,首先需在码表中查到对应的数字是97,然后按照转换成二进制的规则进行存储。称为编码
- 读取的时候,先把二进制解析出来,再转成97,通过97查找早码表中对应的字符是a。称为解码
- ASCII码表:
- ASCII(American Standard Code for Information Interchange,美国信息交换标准码表):
- 包括了数字字符,英文大小写字符和一些常见的标点符号字符。
- 注意:ASCII码表中是没有中文的。
- GBK码表:
- window系统默认的码表。兼容ASCII码表,也包含了21003个汉字,并支持繁体汉字以及部分日韩文字
- 注意:GBK是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
Unicode码表:
- 由国际组织ISO 制定,是统一的万国码表,计算机科学领域里的一项业界标准,容纳世界上大多数国家的所有常见文字和符号。
- 但是因为表示的字符太多,所以Unicode码表中的数字不是直接以二进制的形式存储到计算机的,会先通过UTF-7,UTF-7.5,UTF-8,UTF-16,以及 UTF-32的编码方式再存储到计算机,其中最为常见的就是UTF-8。
- 注意: Unicode是万国码表,以UTF-8编码后一个中文以三个字节的形式存储
1.3 编码表小结
1.4 字节流读中文出现码的原码
- 因为字节流一次读一个字节,而不管GBK还是UTF-8一个中文都是多个字节,用字节流每次只能读其中的一部分,所以就会出现乱码问题
2 字符输出流
2.1 字符流输出介绍
- Writer类
- 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化 , 需要使用其子类FileWriter类
- FileWriter类 : 用来写入字符文件的便捷类
2.2 FileWriter的成员
- 构造方法 :
- public FileWriter(File file) : 往指定的File路径中写入数据
- public FileWriter(String fileName) : 往指定的String路径中写入数据
- 成员方法 :
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
2.3 FileWriter写数据的步骤
- 1 创建字符输出流对象
- 注意事项:
如果文件不存在,就创建。但是要保证父级路径存在。
如果文件存在就清空
- 2 写数据
- 注意事项:
写出int类型的整数,实际写出的是整数在码表上对应的字母。
写出字符串数据,是把字符串本身原样写出。
- 3 释放资源
- 注意事项:
每次使用完流必须要释放资源。
package com.itheima.writer_demo; import java.io.FileWriter; import java.io.IOException; /* Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化 需要使用其子类FileWriter类 FileWriter类 : 用来写入字符文件的便捷类 构造方法 : public FileWriter(File file) : 往指定的File路径中写入数据 public FileWriter(String fileName) : 往指定的String路径中写入数据 成员方法 void write(int c) 写一个字符 void write(char[] cbuf) 写入一个字符数组 void write(char[] cbuf, int off, int len) 写入字符数组的一部分 void write(String str) 写一个字符串 void write(String str, int off, int len) 写一个字符串的一部分 flush() 刷新流,还可以继续写数据 close() 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 */ public class WriterDemo1 { public static void main(String[] args) throws IOException { // 创建字符输出流对象 // 如果文件不存在会创建一个空的文件 // 如果文件存在 , 会把文件中的内容清空 FileWriter fw = new FileWriter("day12_demo\\charstream2.txt"); // 写数据 fw.write('a'); fw.write('b'); // 刷新流 , 把流中的数据刷到硬盘中 , 刷新之后可以继续写数据 // fw.flush(); // 释放资源 // 关闭流 , 但是会先刷新流 fw.close(); // 一旦关闭流无法写数据 // fw.write('c'); } }
package com.itheima.writer_demo; import java.io.FileWriter; import java.io.IOException; /* Writer类 : 写入字符流的最顶层的类 , 是一个抽象类 ,不能实例化 需要使用其子类FileWriter类 FileWriter类 : 用来写入字符文件的便捷类 构造方法 : public FileWriter(File file) : 往指定的File路径中写入数据 public FileWriter(String fileName) : 往指定的String路径中写入数据 成员方法 void write(int c) 写一个字符 void write(char[] cbuf) 写入一个字符数组 void write(char[] cbuf, int off, int len) 写入字符数组的一部分 void write(String str) 写一个字符串 void write(String str, int off, int len) 写一个字符串的一部分 flush() 刷新流,还可以继续写数据 close() 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 */ public class WriterDemo2 { public static void main(String[] args) throws IOException { // 创建字符输出流对象 FileWriter fw = new FileWriter("day12_demo\\charstream2.txt"); // 写数据 // void write(int c) 写一个字符 // fw.write('a'); // fw.write('b'); // fw.write('c'); // void write(char[] cbuf) 写入一个字符数组 char[] chs = {'a', 'b', 'c', 'd', 'e'}; // fw.write(chs); // void write(char[] cbuf, int off, int len) 写入字符数组的一部分 // fw.write(chs , 2 , 3); // void write(String str) 写一个字符串 // fw.write("abcadaasda"); // void write(String str, int off, int len) 写一个字符串的一部分 // fw.write("abnacna", 3, 2); // 释放资源 fw.close(); } }
2.4 字符输出流练习
package com.itheima.writer_demo; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; /* 需求 : 将用户键盘录入的用户名和密码保存到本地实现永久化存储。 要求 : 用户名和密码在文件中各占一行 步骤: 1 用户键盘录入用户名 2 创建字符输出流对象 3 将用户名和密码写到本地文件中 */ public class WriterTest { public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); // 创建字符输出流对象 FileWriter fw = new FileWriter("day12_demo\\user.txt"); // 往文件中写入用户名和密码 fw.write(username); // 换行 fw.write("\r\n"); fw.write(password); // 刷新 fw.flush(); // 释放资源 fw.close(); } }
3 字符输入流
3.1 字节输入流介绍
- Reader类 :
- 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化
- 需要使用其子类FileReader类
- FileReader类 :
- 用来读取字符文件的便捷类
3.2 FileReader的成员
- 构造方法 :
- public FileReader(File file) : 从指定的File路径中读取数据
- public FileReader(String fileName) : 从指定的String路径中读取数据
- 成员方法 :
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
package com.itheima.reader_demo; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /* Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化 需要使用其子类FileReader类 FileReader类 : 用来读取字符文件的便捷类 构造方法 : public FileReader(File file) : 从指定的File路径中读取数据 public FileReader(String fileName) : 从指定的String路径中读取数据 成员方法 : int read() : 一次读一个字符数据 int read(char[] cbuf) : 一次读一个字符数组数据 */ public class ReaderDemo1 { public static void main(String[] args) throws IOException { // 创建字符输入流对象 FileReader fr = new FileReader("day12_demo\\charstream.txt"); // 一次读一个字符数据 int ch; while ((ch = fr.read()) != -1) { System.out.print((char) ch); } // 释放资源 fr.close(); } }
package com.itheima.reader_demo; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /* Reader类 : 读取字符流的最顶层的类 , 是一个抽象类 ,不能实例化 需要使用其子类FileReader类 FileReader类 : 用来读取字符文件的便捷类 构造方法 : public FileReader(File file) : 从指定的File路径中读取数据 public FileReader(String fileName) : 从指定的String路径中读取数据 成员方法 : int read() 一次读一个字符数据 int read(char[] cbuf) 一次读一个字符数组数据 */ public class ReaderDemo2 { public static void main(String[] args) throws IOException { // 创建字符输入流对象 FileReader fr = new FileReader("day12_demo\\charstream.txt"); // 一次读一个字符数组数据 char[] chs = new char[1024]; int len; while ((len = fr.read(chs)) != -1) { System.out.println(new String(chs, 0, len)); } // 释放资源 fr.close(); } }