1.字符流
由于字节流操作中文不是特别方便,所以Java就提供字符流
- 字符流=字节流+编码表
用字节流复制文本文件时,文本文件也会有中文,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文呢?
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
2.编码表
-
基础知识
-
计算机中存储的信息都是用二进制数表示的;我们在屏幕上看到的英文,汉字等字符是二进制数转换之后的结果。
-
按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析出来,称为解码。这里强调一下:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象。
字符编码:就是一套自然语言的字符和二进制数之间的对应规则(A,65)
-
-
字符集:
-
是一个系统支持的所有字符的集合,包括国家文字,标点符号,图形符号,数字等。
-
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。
-
常见的字符集有
ASCII
字符集、GBXXX
字符集、Unicode
字符集等。 -
ASCII
ASCII(American Standard Code for Information Interchange
、美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示线代英文,主要包括控制字符(回车键,退格,换行键等)和显示字符(英文大小写字符,阿拉伯字母和西文符号)- 基本的
ASCII
字符集,使用7位表示一个字符,工128字符。ASCII
的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字,标点符号,图形符号,数字等。
-
GBXXX
字符集GB2312
:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字;这样大约可以组合了包含7000多个简体汉字,此外数学符号,罗马希腊的字母,日文的假名等都编进去了,连在ASCII
里原本就有的数字,标点,字母都统统重新编了两个字节长度的编码,这就是常说的“全交”字符,而原来的127号以下的那些就叫“半角”字符了。GBK
:最常用的中文码表。是GB2312
标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312
标准,同时支持繁体汉字以及日韩汉字等。GB18030
:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个,2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
-
Unicode字符集:
-
为表达任意语言的任意字符而设计,是业界的一种标准,也被称为统一码,标准万国码。它使用最多4个字节的数字来表达每个字母,符号或者文字。有三种编码方案、
UTF-8
、UTF-16
和UTF32
-
UTF-8
编码:可以用来表示Unicode
标准中任意字符,它是电子邮件,网页及其他存储或者传送文字的应用中优先采用的编码。互联网工程小组(IETF
)要求所有互联网协议都必须支持UTF-8
编码。它使用1至4个字节为每个字符编码。-
编码规则:
① 128个US-ASCII
字符,只需要1个字节编码② 拉丁文等字符,需要2个字节编码 ③ 大部分常用字(含中文),使用3个字节编码 ④ 其他极少使用的`Unicode`辅助字符,使用4字节编码
-
-
-
3.字符串中的编码解码问题
-
编码:
byte[]getBytes()
:使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中byte[]getBytes(String charsetName)
:使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中。
-
解码:
String(byte[]bytes)
:通过使用平台默认字符集解码指定的字节数组来构造新的String
String(byte[]bytes,String charsetName)
:通过指定的字符集解码指定的字节数组来构造新的String
package Study04;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/*1. 编码:
- `byte[]getBytes()`:使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
- `byte[]getBytes(String charsetName)`:使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中。
2. 解码:
- `String(byte[]bytes)`:通过使用平台默认字符集解码指定的字节数组来构造新的`String`
- `String(byte[]bytes,String charsetName)`:通过指定的字符集解码指定的字节数组来构造新的`String`*/
public class StringDemo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "中国";
//`byte[]getBytes()`:使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] bytes = s.getBytes();
System.out.println(Arrays.toString(bytes));//[-28, -72, -83, -27, -101, -67]
//`byte[]getBytes(String charsetName)`:使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中。
//UTF-8
byte[] bytes1 = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bytes1));//[-28, -72, -83, -27, -101, -67]
//平台默认的字符集是UTF-8,所以结果一样
//GBK
byte[] bytes2 = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));//[-42, -48, -71, -6]
//`String(byte[]bytes)`:通过使用平台默认字符集解码指定的字节数组来构造新的`String`
String ss = new String(bytes);
System.out.println(ss);//中国
//使用默认字符集解码默认由默认字符集编码的字符
String ss1 = new String(bytes,"UTF-8");
System.out.println(ss1);//中国
//平台默认的编码字符集是UTF-8,所以使用UTF-8解码不会出错
String ss2 = new String(bytes,"GBK");
System.out.println(ss2);//涓浗
//因为编码为默认字符集(UTF-8),解码时使用的是GBK字符集,所以解码结果不正常
String ss3 = new String(bytes2,"GBK");
System.out.println(ss3);//中国
//编码和解码时都使用的GBK,所以解码结果是正确的
}
}
4.字符流中的编码解码问题
字符流抽象基类
Reader
:字符输入流的抽象类Writer
:字符输出流的抽象类
字符流中和编码解码问题相关的两个类
-
InputStreamReader
:是从字节流到字符流的桥梁- 它读取字节,并使用指定的编码将其解码为字符
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
- 构造方法
构造方法 描述 InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader
。InputStreamReader(InputStream in, String charsetName)
创建一个使用命名字符集的 InputStreamReader
。 -
OutputStreamWriter
:是从字符流到字节流的桥梁- 它是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节。
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
- 构造方法
构造方法 | 描述 |
---|---|
OutputStreamWriter(OutputStream out) | 创建一个使用默认字符编码的OutputStreamWriter 。 |
OutputStreamWriter(OutputStream out, String charsetName) | 创建一个使用命名字符集的OutputStreamWriter 。 |
package Study;
import java.io.*;
/*字符流抽象基类
- `Reader`:字符输入流的抽象类
- `Writer`:字符输出流的抽象类
字符流中和编码解码问题相关的两个类
- `InputStreamReader`:是从字节流到字符流的桥梁
- 它读取字节,并使用指定的编码将其解码为字符
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
- 构造方法
| `InputStreamReader(InputStream in)` | 创建一个使用默认字符集的`InputStreamReader`。 |
| `InputStreamReader(InputStream in, String charsetName)` | 创建一个使用命名字符集的`InputStreamReader`。 |
- `OutputStreamWriter`:是从字符流到字节流的桥梁
- 它是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节。
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
- 构造方法
| `OutputStreamWriter(OutputStream out)` | 创建一个使用默认字符编码的`OutputStreamWriter`。 |
| `OutputStreamWriter(OutputStream out, String charsetName)` | 创建一个使用命名字符集的`OutputStreamWriter`。 |
*/
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
/*
| `OutputStreamWriter(OutputStream out)` | 创建一个使用默认字符编码的`OutputStreamWriter`。 |
| `OutputStreamWriter(OutputStream out, String charsetName)` | 创建一个使用命名字符集的`OutputStreamWriter`。 |
*/
/*
FileOutputStream fos = new FileOutputStream("Study\\osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
//改进
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Study\\osw.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Study\\osw.txt"),"UTF-8");//默认使用的字符集是UTF-8
*/
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Study\\osw.txt"),"GBK");//�й�
osw.write("中国");
osw.close();
/*
| `InputStreamReader(InputStream in)` | 创建一个使用默认字符集的`InputStreamReader`。 |
| `InputStreamReader(InputStream in, String charsetName)` | 创建一个使用命名字符集的`InputStreamReader`。 |
*/
//InputStreamReader isr = new InputStreamReader(new FileInputStream("Study\\osw.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("Study\\osw.txt"),"GBK");
//一次读取一个字符数据
int ch;
while ((ch = isr.read())!=-1){
System.out.print((char) ch);
}
isr.close();
}
}
5.字符流写数据的5种方式
-
构造方法
OutputStreamWriter(OutputStream out):
创建一个使用默认字符编码的OutputStreamWriter
-
写数据的5种方法
方法名 | 说明 |
---|---|
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) | 写一个字符串的一部分 |
- 代码示例
package Study;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/*- 构造方法
`OutputStreamWriter(OutputStream out):`创建一个使用默认字符编码的`OutputStreamWriter`
- 写数据的5种方法
| 方法名 | 说明 |
| --------------------------------------------- | -------------------- |
| `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)` | 写一个字符串的一部分 |
*/
public class ConversionStreamDemo01 {
public static void main(String[] args) throws IOException {
//`OutputStreamWriter(OutputStream out):`创建一个使用默认字符编码的`OutputStreamWriter`
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Study\\osw.txt"));
//| `void write(int c)` | 写一个字符 |
/*osw.write(97);//a
osw.write(99);//c
//void flush();刷新流
osw.flush();*/
//| `void write(char[] cbuf)` | 写入一个字符数组 |
/*char [] ch = {'a','b','c','d'};//abcd
osw.write(ch);*/
//| `void write(char[] cbuf , int off , int len)` | 写入字符数组的一部分 |
/*char [] ch = {'a','b','c','d'};
osw.write(ch,1,2);//bc*/
//| `void write(String str)` | 写入一个字符串 |
/*osw.write("abcd");//abcd*/
//| `void write(String str , int off , int len)` | 写一个字符串的一部分 |
osw.write("abcd",1,2);//bc
osw.close();
/*close()方法和flush()方法的区别
1.flush()方法只刷新,刷新完后还能继续添加数据
2.close()方法先刷新后释放资源,释放资源后不能再写入数据
* */
}
}
方法名 | 说明 |
---|---|
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
6.字符流读数据的2种方式
-
构造方法
InputStreamReader(InputStream in)
:创建一个使用默认字符集的InputStreamReader
-
读数据的2种方式
方法名 | 说明 |
---|---|
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 字词读一个字符数组数据 |
- 代码示例
package Study;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
/*
1. 构造方法
`InputStreamReader(InputStream in)`:创建一个使用默认字符集的`InputStreamReader`
2. 读数据的2种方式
| 方法名 | 说明
| `int read()` | 一次读一个字符数据
| `int read(char[] cbuf)` | 字词读一个字符数组数据
*/
public class ConversionStreamDemo02 {
public static void main(String[] args) throws IOException {
//`InputStreamReader(InputStream in)`:创建一个使用默认字符集的`InputStreamReader`
// InputStreamReader isr = new InputStreamReader(new FileInputStream("Study\\osw.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("Study\\ConversionStreamDemo.java"));
//| `int read()` | 一次读一个字符数据
/*int ch;
while ((ch=isr.read())!=-1){
System.out.print((char) ch);
}*/
//| `int read(char[] cbuf)` | 字词读一个字符数组数据
char [] chr = new char[1024];
int len;
while ((len=isr.read(chr))!=-1){
System.out.println(new String(chr,0,len));
}
//释放资源
isr.close();
}
}
/*字节流读数据和字符流读数据格式相同*/
7.案例:字符流复制Java文件
-
需求:把模块目录下的
ConversionStreamDemo.java
复制到模块目录下的Copy.java
-
思路:
- 根据数据源创建字符输入流对象
- 根据数据源创建字符输出流对象
- 读写数据,复制文件
- 释放资源
- 代码
package Study;
import java.io.*;
/*
1. 需求:把模块目录下的`ConversionStreamDemo.java`复制到模块目录下的`Copy.java`
2. 思路:
- 根据数据源创建字符输入流对象
- 根据数据源创建字符输出流对象
- 读写数据,复制文件
- 释放资源*/
public class ConversionStreamDemo03 {
public static void main(String[] args) throws IOException {
//- 根据数据源创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("Study\\ConversionStreamDemo.java"));
//- 根据数据源创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Study\\Copy.java"));
//- 读写数据,复制文件
//一次读写一个字符
/*int chr;
while ((chr=isr.read())!=-1){
osw.write(chr);
}*/
//一次读写一个字符数组
char []ch = new char[1024];
int len;
while ((len=isr.read(ch))!=-1){
osw.write(ch,0,len);
}
//- 释放资源
isr.close();
osw.close();
}
}
-
改进版
-
分析
-
转换流的名字较长,而我们常见的操作都是按照本地默认编码实现的,所以为了简化书写,转换流提供了对应的子类
-
FileReader
:用于读取字符文件的便捷类FileReader(String fileName)
-
FileWriter
:用于写入字符文件的便捷类FileWriter(String fileName)
-
数据源和目的地的分析
-
数据源:
Study\\ConversionStreamDemo.java
——读数据——Reader
——InputStreamReader
——FileReader
-
目的地:
Study\\Copy.java
——写数据——Writer
——OutputStreamWriter
——FileWriter
-
-
-
思路
- 根据数据源创建字符输入流对象
- 根据目的地创建字符数出流对象
- 读写数据,复制文件
- 释放资源
-
代码
package Study; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /* 需求:把模块目录下的`ConversionStreamDemo.java`复制到模块目录下的`Copy.java` 数据源和目的地的分析 - 数据源:`Study\\ConversionStreamDemo.java`——读数据——`Reader`——`InputStreamReader`——`FileReader` - 目的地:`Study\\Copy.java`——写数据——`Writer`——`OutputStreamWriter`——`FileWriter` 思路 - 根据数据源创建字符输入流对象 - 根据目的地创建字符数出流对象 - 读写数据,复制文件 - 释放资源 */ public class ConversionStreamDemo04 { public static void main(String[] args) throws IOException { //- 根据数据源创建字符输入流对象 FileReader fr = new FileReader("Study\\ConversionStreamDemo.java"); //- 根据目的地创建字符数出流对象 FileWriter fw = new FileWriter("Study\\\\Copy.java"); //- 读写数据,复制文件 //一次读写一个字符数组 char []ch = new char[1023]; int len; while ((len= fr.read(ch))!=-1){ fw.write(ch,0,len); } //- 释放资源 fw.close(); fr.close(); } }
-
8.字符缓冲流
字符缓冲流:
BuffereWriter
:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。BufferedReader
:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途。
构造方法
BufferedWriter(Writer out)
BufferedReader(Reader in)
代码
package Study;
import java.io.*;
/*
字符缓冲流:
- `BuffereWriter`:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。
- `BufferedReader`:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途。
构造方法
- `BufferedWriter(Writer out)`
- `BufferedReader(Reader in)`
*/
public class ConversionStreamDemo05 {
public static void main(String[] args) throws IOException {
//- `BufferedWriter(Writer out)`
/* FileWriter fw = new FileWriter("Study\\dw.txt");
BufferedWriter bw = new BufferedWriter(fw);*/
/*BufferedWriter bw = new BufferedWriter(new FileWriter("Study\\dw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();*/
//- `BufferedReader(Reader in)`
BufferedReader br = new BufferedReader(new FileReader("Study\\dw.txt"));
//一次读取一个字符数据
/*int chs;
while ((chs=br.read())!=-1){
System.out.print((char) chs);
}*/
//一次读取一个字符数组数据
char[] ch = new char[1024];
int len;
while ((len = br.read(ch)) != -1) {
System.out.println(new String(ch, 0, len));
}
br.close();
}
}
9.案例:字符缓冲流复制Java文件
-
需求:把模块目录下的
ConversionStreamDemo.java
复制到模块目录下的Copy.java
-
思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件
- 释放资源
package Study;
import java.io.*;
/*
1. 需求:把模块目录下的`ConversionStreamDemo.java`复制到模块目录下的`Copy.java`
2. 思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件
- 释放资源*/
public class ConversionStreamDemo06 {
public static void main(String[] args) throws IOException {
// - 根据数据源创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("Study\\ConversionStreamDemo.java"));
//- 根据目的地创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Study\\Copy.java"));
//- 读写数据,复制文件
//一次读写一个字符数据
/*int chr;
while ((chr=br.read())!=-1){
bw.write(chr);
}*/
//一次读写一个字符数组数据
char[]ch = new char[1024];
int len;
while ((len=br.read(ch))!=-1){
bw.write(ch,0,len);
}
// 释放资源
bw.close();
br.close();
}
}
10.字符缓冲流特有功能
BufferedWriter
:
void newList()
:写一行分隔符,分隔符字符由系统属性定义
BufferedReader
:
public String readLine()
:读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
package Study;
import java.io.*;
/*
`BufferedWriter`:
- `void newList()`:写一行分隔符,分隔符字符由系统属性定义
`BufferedReader`:
- `public String readLine()`:读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
*/
public class ConversionStringDemo07 {
public static void main(String[] args) throws IOException {
/*//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Study\\dd.txt"));
//- `void newList()`:写一行分隔符,分隔符字符由系统属性定义
for (int i = 0;i<10;i++){
bw.write("hello"+i);
//bw.write("\r\n");
bw.newLine();
}
//释放资源
bw.close();*/
//创建媳妇缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("Study\\dd.txt"));
//- `public String readLine()`:读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
//释放资源
br.close();
}
}
11.案例:字符缓冲流特有功能复制Java文件
-
需求:把模块目录下的
ConversionStreamDemo.java
复制到模块目录下的Copy.java
-
思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件
- 使用字符缓冲流特有功能实现
- 释放资源
- 代码
package Study;
import java.io.*;
/*
1. 需求:把模块目录下的`ConversionStreamDemo.java`复制到模块目录下的`Copy.java`
2. 思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件
- 使用字符缓冲流特有功能实现
- 释放资源
*/
public class ConversionStringDemo08 {
public static void main(String[] args) throws IOException {
//- 根据数据源创建字符缓冲输入流对象
BufferedReader buf = new BufferedReader(new FileReader("Study\\ConversionStreamDemo.java"));
//- 根据目的地创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Study\\Copy.java"));
//- 读写数据,复制文件
// - 使用字符缓冲流特有功能实现
String line;
while ((line = buf.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//- 释放资源
bw.close();
buf.close();
}
}
12.IO小结
- 字节流小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHwB7jGk-1637632531522)(D:\Java\Java笔记\个人笔记\1.Java基础和进阶笔记\笔记涉及图片\字节流小结.png)]
小结:字节流可以复制任意文件数据,有4种方式,一般采取字节缓冲流一次读写一个字节数组的方式。
- 字符流小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69SBxiHG-1637632531524)(D:\Java\Java笔记\个人笔记\1.Java基础和进阶笔记\笔记涉及图片\字符流小结.png)]
小结:字符流只能复制文本数据,有5种方式,一般采用字符缓冲流的特有功能。
new FileReader(“Study\ConversionStreamDemo.java”));
//- 根据目的地创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter(“Study\Copy.java”));
//- 读写数据,复制文件
// - 使用字符缓冲流特有功能实现
String line;
while ((line = buf.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//- 释放资源
bw.close();
buf.close();
}
}
# 12.IO小结
1. 字节流小结:
![在这里插入图片描述](https://img-blog.csdnimg.cn/5e88ceb28aba4a6db379086dfe3c0684.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bm65rSe5Lik6IKG,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
小结:字节流可以复制任意文件数据,有4种方式,一般采取字节缓冲流一次读写一个字节数组的方式。
2. 字符流小结:
![在这里插入图片描述](https://img-blog.csdnimg.cn/04579b767748422a990d7de2272425bf.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bm65rSe5Lik6IKG,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
小结:字符流只能复制文本数据,有5种方式,一般采用字符缓冲流的特有功能。