字节缓冲流
构造方法
-  
字节缓冲流介绍
- BufferedOutputStream:该类实现缓冲输出流.通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
 - BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组.当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
 
 -  
构造方法:
方法名 说明 BufferedOutputStream(OutputStream out) 创建字节缓冲输出流对象 BufferedInputStream(InputStream in) 创建字节缓冲输入流对象  -  
读写和关闭流的方法 同字节输入输出流
 
代码
- 用BufferedOutputStream写数据到文件
 - 用BufferedInputStream把刚才写入的文件读出来
 
//缓冲字节输出流对象 创建
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("module01/aaa.txt"));
//写入
bos.write(99);
bos.write(100);
bos.write(101);
//关闭
bos.close();
//缓冲字节输入流对象 创建   用来读取aaa.txt
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("module01/aaa.txt"));
//循环读取aaa.txt
int b;
while ((b = bis.read()) != -1) {
    System.out.println((char)b);
}
//关闭流
bis.close();
 
缓冲流原理
-  
减少了对硬盘的操作,写入数据到数组
 -  
1 数组满了之后,才会自动写入到硬盘
 -  
2 主动调用flush后 也会写入到硬盘 注意close方法中 已经调用了flush

 -  
每次从数组里读,这样操作的是内存,效率高,直到把数组内容读完,数组在去硬盘获取
 

flush方法
- 调用flush方法,可以主动把数据写入到硬盘
 - close方法里也调用了flush方法
 
字节缓冲流复制一个视频练习
一次一个字节代码
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("module01/music/无间道.mp3"));
        //缓冲字节输出流对象 创建
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("module01/music/无间道1.mp3"));
        int b;
        while ((b = bis.read()) != -1) {
            //把读取的内容写入到无间道1.mp3
            bos.write(b);
        }
        bos.close();
        bis.close();
    }
 
一次一个数组代码
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("module01/music/无间道.mp3"));
        //缓冲字节输出流对象 创建
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("module01/music/无间道1.mp3"));
        byte[] b = new byte[1024];
        int len;
        while ((len = bis.read(b)) != -1) {
            //把读取的内容写入到无间道1.mp3
            bos.write(b, 0, len);
        }
        bos.close();
        bis.close();
    }
 
字符流
介绍
- 由于字节流操作中文不是特别的方便,所以Java就提供字符流 
  
- 字符流 = 字节流 + 编码表
 
 - 中文的字节存储方式 
  
- 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
 - 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
 
 
编码表(了解)
-  
什么是字符集
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
l计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
 -  
常见的字符集
-  
ASCII字符集:
lASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
 -  
GBXXX字符集:
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
 -  
Unicode字符集:
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
 
 -  
 
编码规则:
- 128个US-ASCII字符,只需一个字节编码
 - 拉丁文等字符,需要二个字节编码
 - 大部分常用字(含中文),使用三个字节编码
 - 其他极少使用的Unicode辅助字符,使用四字节编码
 
字符串中的编码解码问题(会使用)
-  
相关方法
方法名 说明 byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节 byte[] getBytes(String charsetName) 使用指定的字符集将该 String编码为一系列字节 String(byte[] bytes) 使用平台的默认字符集解码指定的字节数组来创建字符串 String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来创建字符串  
代码
- encode编码 decode解码
 
String str01 = "我爱我的祖国";
byte[] bytes = str01.getBytes("utf-8");
System.out.println(Arrays.toString(bytes));
byte[] bytes1 = str01.getBytes("gbk");
System.out.println(Arrays.toString(bytes1));
String str02 = new String(bytes,"utf-8");
System.out.println(str02);
String str03 = new String(bytes1,"gbk");
System.out.println(str03);
 
idea设置编码

字符流类
-  
Writer和Reader
 -  
字节流 操作一切文件
 -  
字符流 操作文本文件 操作汉字时更方便
 
FileWriter
- Writer: 用于写入字符流的抽象父类
 - FileWriter: 用于写入字符流的常用子类
 
构造方法
| 方法名 | 说明 | 
|---|---|
| FileWriter(File file) | 根据给定的 File 对象构造一个 FileWriter 对象 | 
| FileWriter(File file, boolean append) | 根据给定的 File 对象构造一个 FileWriter 对象 | 
| FileWriter(String fileName) | 根据给定的文件名构造一个 FileWriter 对象 | 
| FileWriter(String fileName, boolean append) | 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 | 
jdk11后构造方法可以指定编码
    public static void main(String[] args) throws IOException {
        //jdk11后 支持指定编码解码方式
        //参数2指定编码为utf-8 注意语法是Charset.forName()
        FileWriter fw = new FileWriter("qqqqqq.txt", Charset.forName("utf-8"));
        fw.write("开心的文字 拆迁啦");
        fw.close();
        //参数2 指定解码方式为utf-8
        FileReader fr = new FileReader("qqqqqq.txt", Charset.forName("utf-8"));
        char[] cs = new char[1000];
        int len = fr.read(cs);
        fr.close();
        System.out.println(new String(cs, 0, len));
    }
 
成员方法
| 方法名 | 说明 | 
|---|---|
| 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() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 | 
代码
//FileWriter fw = new FileWriter(new File("module01/ccc.txt"));
FileWriter fw = new FileWriter("module01/ccc.txt");
fw.write(100);
char[] cs = {'a', 'g', '啊', '吃'};
fw.write(cs);
fw.write("饭了,吃烤鸭,吃宫爆鸡丁,吃鱼香肉丝");
fw.write("\r\n"); //写入换行
fw.write("abcdefg", 1, 3);//跳过1个写入3个
fw.close();
 
FileWrite本身就有缓冲区
- 如果write少量数据,没有flush也没有close,会发现没有写入文件
 - close方法执行后,不能继续使用流对象了
 
FileReader
- Reader: 用于读取字符流的抽象父类
 - FileReader: 用于读取字符流的常用子类
 
构造方法
| 方法名 | 说明 | 
|---|---|
| FileReader(File file) | 在给定从中读取数据的 File 的情况下创建一个新 FileReader | 
| FileReader(String fileName) | 在给定从中读取数据的文件名的情况下创建一个新 FileReader | 
成员方法
| 方法名 | 说明 | 
|---|---|
| int read() | 一次读一个字符数据 | 
| int read(char[] cbuf) | 一次读一个字符数组数据 | 
代码演示
//FileReader fr = new FileReader(new File("module01/ccc.txt"));
FileReader fr = new FileReader("module01/ccc.txt");
//int a;
//while ((a = fr.read()) != -1) {
//    System.out.println(a);
//    System.out.println((char) a);
//}
//System.out.println("\r\n".toCharArray().length);
char[] cs = new char[3];
int len;
while ((len = fr.read(cs)) != -1) {
    //System.out.println(cs);
    System.out.println(new String(cs, 0, len));//转为字符串 注意要添加len长度,最后一次遍历数组可能装不满
}
fr.close();
 
字符流用户注册案例
-  
案例需求
将键盘录入的用户名和密码保存到本地实现永久化存储
 -  
实现步骤
- 1获取用户输入的用户名和密码
 - 2将用户输入的用户名和密码写入到本地文件中
 - 3关流,释放资源
 
 
代码
//- 1获取用户输入的用户名和密码
//- 2将用户输入的用户名和密码写入到本地文件中
//- 3关流,释放资源
Scanner sc = new Scanner(System.in);
System.out.println("输入的用户名:");
String name = sc.next();
System.out.println("输入的密码:");
String pwd = sc.next();
try(FileWriter fw = new FileWriter("user.txt");) {
    //写入用户名
    fw.write(name);
    //换行
    fw.write("\r\n");
    //写入密码
    fw.write(pwd);
} catch (IOException e) {
    e.printStackTrace();
} 
 
FileOutputStream
BufferedOutputStream
FileWrite  字符流本身就有一个缓冲数组  8kb
BufferedWrite
 
字符缓冲流
-  
介绍
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
 - BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
 
 -  
构造方法
方法名 说明 BufferedWriter(Writer out) 创建字符缓冲输出流对象 BufferedReader(Reader in) 创建字符缓冲输入流对象  
代码
- BufferedWriter写数据
 - BufferedReader读数据
 
try (BufferedReader br = new BufferedReader(new FileReader("mymodule/d.txt"));
     BufferedWriter bw = new BufferedWriter(new FileWriter("mymodule/d1.txt"));) {
    //定义字符数组
    char[] cs = new char[1024];
    //定义长度
    int len = 0;
    while ((len = br.read(cs)) != -1) {
        bw.write(cs, 0, len);
    }
} catch (IOException e) {
    e.printStackTrace();
}
 
字符缓冲流特有功能
-  
方法介绍
BufferedWriter:
方法名 说明 void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义 BufferedReader:
方法名 说明 String readLine() 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null  
代码
- 1循环写入10次hello world到文件,每次都换行
 - 2按行读取文件内容
 
//    - 1循环写入10次hello world到文件,每次都换行
//创建缓冲字符写入流
try(bw = new BufferedWriter(new FileWriter("module01/xxx.txt"));){
    for (int i = 0; i < 10; i++) {
        bw.write("hello world");
        //换行
        bw.newLine();
    }
} catch (IOException e) {
    e.printStackTrace();
} 
// - 2按行读取文件内容
try( //创建缓冲字符读取流
    BufferedReader br = new BufferedReader(new FileReader("module01/xxx.txt"));) {
    //定义字符串接收读取的内容
    String line;
    //每次读取一行  内容全部读完后,如果再读 就会返回null 把循环结束
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
} 
 
字符缓冲流操作文件中数据排序案例
需求
- 使用字符缓冲流读取文件中的数据,排序后再次写到本地文件
 - 文件内容是 
5 32 47 7 5 22 2 12 4 8 6 
步骤
- 1将文件中的数据读取到程序中
 - 2对读取到的数据进行分割转换排序
 - 3将排序后的数据写入到文件中
 
代码
//1 读取文件内容  按行读取
try (
    BufferedReader br = new BufferedReader(new FileReader("mymodule/ee.txt"));
) {
    String line = br.readLine();//读取数据5 32 47 7 5 22 2 12 4 8 6
    //2 把读取的字符串 按空格切割 得到一个字符串数组
    String[] ss = line.split(" ");
    System.out.println(Arrays.toString(ss));
    //把字符串的数组转为int数组
    int[] arr = new int[ss.length];
    for (int i = 0; i < ss.length; i++) {
        arr[i] = Integer.parseInt(ss[i]);
    }
    //3 对字符串数组排序
    Arrays.sort(arr);
    System.out.println(Arrays.toString(arr));
    //4 把排序完的数据写回文件
    BufferedWriter bw = new BufferedWriter(new FileWriter("mymodule/ee.txt"));
    for (int i : arr) {
        //遍历写回内容 注意加空格
        bw.write(i + " ");
    }
    //关闭流
    bw.close();
} catch (IOException e) {
}
 
#转换流(理解)
两个类(可以在读写时,指定编码集)
- InputStreamReader
 - OutputStreamWriter
 
jdk11后使用
- FileWriter 和FileReader
 
构造方法
| 方法名 | 说明 | 
|---|---|
| InputStreamReader(InputStream in) | 使用默认字符编码创建InputStreamReader对象 | 
| InputStreamReader(InputStream in,String chatset) | 使用指定的字符编码创建InputStreamReader对象 | 
| OutputStreamWriter(OutputStream out) | 使用默认字符编码创建OutputStreamWriter对象 | 
| OutputStreamWriter(OutputStream out,String charset) | 使用指定的字符编码创建OutputStreamWriter对象 | 
代码演示
- 用OutputStreamWriter 写入汉字 指定编码
 - 用InputStreamReader 读取汉字 指定编码
 
public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        
        //创建写入的转换流对象 使用默认编码
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"));
        //创建写入的转换流对象  指定编码为gbk
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"),"GBK");
        osw.write("中国");
        osw.close();
        //创建读取的转换流对象 使用默认编码
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"));
        //创建读取的转换流对象  指定编码为gbk
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"),"GBK");
        //一次读取一个字符数据
        int ch;
        while ((ch=isr.read())!=-1) {
            System.out.print((char)ch);
        }
        isr.close();
    }
}
 
注意:jdk11后用文件读写流就可以指定编码了
    public static void main(String[] args) throws IOException {
        //jdk11后 支持指定编码解码方式
        //参数2指定编码为utf-8 注意语法是Charset.forName()
        FileWriter fw = new FileWriter("qqqqqq.txt", Charset.forName("utf-8"));
        fw.write("开心的文字 拆迁啦");
        fw.close();
        //参数2 指定解码方式为utf-8
        FileReader fr = new FileReader("qqqqqq.txt", Charset.forName("utf-8"));
        char[] cs = new char[1000];
        //读取数据到数组
        int len = fr.read(cs);
        //关闭流
        fr.close();
        System.out.println(new String(cs, 0, len));
    }
 

对象操作流
Serializable  可序列化的  形容词
Serializer    序列化器   名词
Serialize     序列化    动词
对象 -- 》 字节序列  就可以保存 在文件里  也可以在网络中传输
 新闻
class News Implements Serializable{
String  tilte;
Strint content;
Date  date;
}
News n = new News();
 //创建对象输出流
 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("news.txt"));
 //把对象写入
 oos.writeObject(n);
 //关闭流
 oos.close();
 
 
 javasscript
前端收到的是新闻的字节数据  
把字节数据 转回成对象   反序列化
 
对象序列化流
-  
对象序列化介绍
- 对象序列化:把对象转换为可以存储或传输的形式的过程
 - 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
 - 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
 
 -  
对象序列化流: ObjectOutputStream
- 将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
 
 -  
构造方法
方法名 说明 ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream  -  
序列化对象的方法
方法名 说明 void writeObject(Object obj) 将指定的对象写入ObjectOutputStream  
代码
- 动物类
 
public class Anima implements Serializable {
    public String name;
    protected int age;
    public Anima() {
    }
    public Anima(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Anima{" +
                "name='" + name + '\'' +
                ", age=" + age;
    }
}
 
测试类
public class Demo01 {
    public static void main(String[] args) throws IOException {
        //创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("animal.txt"));
        //Anima类要实现Serializable接口
        Anima a = new Anima("大象", 3);
        //把对象写入
        oos.writeObject(a);
        //关闭流
        oos.close();
    }
}
 
注意事项
- 一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
 - Serializable是一个标记接口,实现该接口,不需要重写任何方法
 
对象反序列化流
-  
对象反序列化流: ObjectInputStream
- ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
 
 -  
构造方法
方法名 说明 ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream  -  
反序列化对象的方法
方法名 说明 Object readObject() 从ObjectInputStream读取一个对象  
代码
//创建对象输出流
ObjectInputStream oos = new ObjectInputStream(new FileInputStream("animal.txt"));
//读取出对象 然后强转为Anima对象  这个过程也叫反序列化
Anima a = (Anima) oos.readObject();
oos.close();
//打印读取的对象
System.out.println(a);
 
serialVersionUID&transient
- serialVersionUID 
  
- 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢? 
    
- 会出问题,会抛出InvalidClassException异常
 
 
 - 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢? 
    
 
Exception in thread "main" java.io.InvalidClassException: com.heima1.test3.Anima; local class incompatible: stream classdesc serialVersionUID = 4726774650000051461, local class serialVersionUID = -3497608134273938572
 
-  
如果出问题了,如何解决呢?
-  
1给对象所属的类加一个serialVersionUID
- private static final long serialVersionUID = 42L;
 
 -  
2重新序列化,再次测试
 
 -  
 
transient
- 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢? 
  
- 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
 
 
代码
- 学生类
 
public class Anima implements Serializable {
    public static final long serialVersionUID = 42L;
    public String name;
    public int age;
    //transient表示在序列化的时候,忽略当前的字段
    public transient int weight;
    public Anima(String name, int age, int weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }
    public Anima() {
    }
    @Override
    public String toString() {
        return "Anima{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", weight=" + weight +
                '}';
    }
 
- 序列化测试 
  
- Anima对象 有一个400斤的体重,然后执行writeObject保存
 
 
        //创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("xiongda.txt"));
        //Anima类要实现Serializable接口
        Anima a = new Anima("熊大", 7, 400);
        //把对象写入
        oos.writeObject(a);
        oos.close();
 
- 反序列化测试 
  
- 读取对象后打印,发现体重为0.0
 - 应为weight被transient修饰,数据没有被保存
 
 
        //创建对象输出流
        ObjectInputStream oos = new ObjectInputStream(new FileInputStream("xiongda.txt"));
        //读取出对象 然后强转为Anima对象  这个过程也叫反序列化
        Anima a = (Anima) oos.readObject();
        oos.close();
        //打印读取的对象
        System.out.println(a);//Anima{name='熊大', age=7, weight=0}
 
对象操作流练习
案例需求
- 创建多个学生类对象写到文件中,再次读取到内存中
 
步骤
- 1创建序列化流对象
 - 2创建多个学生对象
 - 3将学生对象添加到集合中
 - 4将集合对象序列化到文件中
 - 5创建反序列化流对象
 - 6将文件中的对象数据,读取到内存中
 
代码实现
- 学生类
 
public class Student implements Serializable{
    
    private static final long serialVersionUID = 2L;
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
 
- 测试类
 
public class Demo01 {
    public static void main(String[] args) {
        //创建多个学生类对象写到文件中,再次读取到内存中
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            //- 1创建序列化流对象
            oos = new ObjectOutputStream(new FileOutputStream("module01/stu.data"));
            //- 2创建多个学生对象
            Student stu01 = new Student("xiaoming", 20);
            Student stu02 = new Student("xiaohong", 21);
            Student stu03 = new Student("pgo", 30);
            //- 3将学生对象添加到集合中
            ArrayList<Student> stus = new ArrayList<>();
            stus.add(stu01);
            stus.add(stu02);
            stus.add(stu03);
            //- 4将集合对象序列化到文件中
            oos.writeObject(stus);
            //- 5创建反序列化流对象
            ois = new ObjectInputStream(new FileInputStream("module01/stu.data"));
            //- 6将文件中的对象数据,读取到内存中
            ArrayList<Student> ss = (ArrayList<Student>) ois.readObject();
            System.out.println(ss);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("读写失败");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("找不到class");
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
 
小结
字节流
FileOutputStream  FileInputStream   read  write
BufferedOutputStream  BufferedInputStream
字符流
FileReader  FileWriter
BufferedReader  readLine  BufferedWriter  newLine
转换流
InputStreamReader  OutputStreamWriter
对象流
ObjectInputStream  ObjectOutputStream
                

















