IO-3

回顾:
学习了流:
IO --> input 和 output
IO相当于管道 作为 硬盘和内存之间一种连通的方式
将数据固化到磁盘,将磁盘中的数据在读取回来
InputStream 和 OutoutStream 字节输入输出流(父类) --> 抽象类不能直接new
Reader 和 Writer 字符输入输出流(父类) --> 抽象类不能直接new
read读取(磁盘的数据读取到内存中) 数组 --> byte 和 char
返回值 ---> 实际读取的长度 正常读取时实际长度 读取文件的末尾返回-1
进行一个循环读取
writer写出(将存储在数组中的数据写出去) 数组 --->byte 和 char
子类:

文件字节输入输出流:FileInputStream 和 FileOutputStream -->完全参考父类流中的方法来使用
FileOutputStream创建对象时,可以做为数据的追加 --> boolean -->true 追加 不写或是false 不追加
文件字符输入输出流:FileReader 和 FileWritrer --->完全参考父类流中的方法

标准输入输出流
System.in 和 System.out (重定向)
改变流流向从而让系统流得到不同的数据获取方式
System.in --> InputStream 字节输入流
System.setIn(字节输入流对象)
System.out --> PrintStream(字节打印流)--->OutputStream(子类)
System.setOut(字节打印流对象)

转换流---> 字符编码 ---> GBK,UTF-8
InputStreamReader 字节流转换字符流 --->父类是 Reader(字符流)
OuputStreamWriter 字符流转换字节流 --->父类是 Writer(字符流)
可以在读取文件是 指定读取文件的字符编码 在写出文件时 指定写出文件的字符编码
调用当前两个流的 两个参数版本的构造方法
直接以字符串的形式指定字符编码"UTF-8"
使用Charset类中的forName来指定字符串编码 Charset.forName("GBK")
只有读取时指定编码正确,你才能在写出时改变字符编码
读取是字符编码错误了,无论如何写出都是错误

内存流 ---> 将数据存储到内存中 ---> 数组 , 字符串
ByteArrayInputStream 和 ByteArrayOutputStream --> 数组内存字节输入输出流
CharArrayReader 和 CharArrayWiter --> 数组内存字符输入输出流
StringReader 和 StringWriter --> 字符串内存输入输出流
内存中存储数据的读写速度 是绝对大于 磁盘中存储数据的读写速度
只要是磁盘就会进行IO
内存存储数据最大弊端:掉电易失-->电源掉了,存储到内存中数据就全部的消失

字节缓冲输入输出流
缓冲区: --> 将数据读取到这个缓冲区中,通过这个缓冲区加快对流的操作(流的流速加快了)
BufferedInputStream
BufferedOutputStream
这两个流的使用方式完全可以参考InputStream和OutputStream


字符缓冲输入输出流
自带缓冲区
BufferedReader 字符缓冲输入流

构造方法
BufferedReader(Reader in) 传入字符流对象创建字符缓冲流对象
BufferedReader(Reader in, int sz)传入字符流对象创建字符缓冲流对象,并设置缓冲区大小
常用方法:
void close() 关闭流
int read() 读取单个字符
int read(char[] cbuf); 读取字符数组的长度的内容
int read(char[] cbuf, int off, int len)读取数组的长度 从什么位置开始 写到什么位置

特殊方法:
读取一行 String readLine() 读取一个文本行。 返回的是String类型

BufferedReade 字符缓冲输出流
构造方法:
BufferedWriter(Writer out) 通过字符输入流创建字符缓冲输入流对象
BufferedWriter(Writer out, int sz) 通过字符输入流创建字符缓冲输入流对象,并指定缓冲区大小

/**
 * 
 */
package com.qfedu.Day20.IO.BufferedOutputStream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * Description: 字节输出缓冲流<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:BufferedOutputStreamDemo.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class BufferedOutputStreamDemo {
    public static void main(String[] args)throws Exception {
        //在控制台上获取数据-->bis流对象就可以在控制台上获取数据
        //ps:Scanner --> 在控制台上获取数据
        BufferedInputStream bis = new BufferedInputStream(System.in);
        PrintStream ps = new PrintStream(new FileOutputStream(new File("dir/字节缓冲流输出的数据.txt")));
        System.setOut(ps);
        //构建标准输出流
        BufferedOutputStream bos = new BufferedOutputStream(System.out);
        //在控制台上输入数据输入什么就写入到对应的文件中
        byte[] bs = new byte[1024];
        int len = 0;
        while(true) {
            //获取控制台输入
            len = bis.read(bs);
           //创建一个字符串
            String content = new String(bs,0,len);
            //只要是输入886,这个程序就停止
            //获取到换行符  

            if("886
".equals(content)) {
                break;
            }
            bos.write(content.getBytes());
            bos.flush();
        }    
        bos.close();
        bis.close();
        
    }

}


常用方法:
close() 关闭此流
void flush() 刷新流
void write(char[] cbuf, int off, int len) 写入字符数组的长度,从什么位置开始写, 写多长
void write(int c) 写单个字符
void write(String s, int off, int len) 写入字符串,从什么位置写,写多长

特有方法:
void newLine() 写入一个行分隔符。

需求:现在所有异常一律抛出 throws,先在当前工程下创建一个文件夹dir,
将当前程序使用字符缓冲输入输出流循环读取并写入到dir文件夹下
ps写流的步骤:
1.创建流对象(确定流的流向和数据类型)
2.循环读取文件中的数据 --> 定义一个变量来获取实际读取的长度
判断是否读取到文件的末尾-1
如果没有 将数据写出去
3.关闭流
看BufferedReaderAndWriterDemo类

/**
 * 
 */
package com.qfedu.Day21.IO.BufferedReaderAndWriter;

import java.io.*;

/**
 * Description: 字符缓冲输入输出流<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:BufferedReaderAndWriterDemo.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class BufferedReaderAndWriterDemo {
    public static void main(String[] args) throws Exception {
        /*
         * 需求:现在所有异常一律抛出 throws,先在当前工程下创建一个文件夹dir,
              将当前程序使用字符缓冲输入输出流循环读取并写入到dir文件夹下
         */
        //ReaderAndWriterOld(); //老读写方式
        ReaderAndWriterNew();  //新读写方式
        

    }
    public static void ReaderAndWriterOld() throws Exception {
        /*
         * ps写流的步骤:
                  1.创建流对象(确定流的流向和数据类型)
                  2.循环读取文件中的数据  --> 定义一个变量来获取实际读取的长度
                                判断是否读取到文件的末尾-1
                                 如果没有 将数据写出去
                  3.关闭流        
          通过BufferedReader对 传入参数的流进行一次包装,让当前流具备了缓冲流,从而提高了流的流速
             缓冲流也称之为包装流                        
         */
        //读取
        BufferedReader  br  = 
                new BufferedReader(
                        new FileReader(
                                new File("src/com/qfedu/Day21/IO/BufferedReaderAndWriter/BufferedReaderAndWriterDemo.java")));
        
        //写入
        BufferedWriter bw = 
                new BufferedWriter(
                        new FileWriter(
                                new File("dir/BufferedReaderAndWriter.java")));
        char[] cbuf = new char[1024];
        int len = 0;
        while((len = br.read(cbuf))!=-1) {
            bw.write(cbuf,0,len);
        }
        bw.flush();
        bw.close();
        br.close();
    }
    //系统中提供了两个特有的方法
    //读取: readLine(); -->读取一行字符串
    //写出: newLine();  --> 写入一个换行符
    public static void ReaderAndWriterNew() throws Exception {
        /*
         * ps写流的步骤:
                  1.创建流对象(确定流的流向和数据类型)
                  2.循环读取文件中的数据  --> 定义一个变量来获取实际读取的长度
                                判断是否读取到文件的末尾-1
                                 如果没有 将数据写出去
                  3.关闭流        
          通过BufferedReader对 传入参数的流进行一次包装,让当前流具备了缓冲流,从而提高了流的流速
             缓冲流也称之为包装流                        
         */
        //读取
        BufferedReader  br  = 
                new BufferedReader(
                        new FileReader(
                                new File("src/com/qfedu/Day21/IO/BufferedReaderAndWriter/BufferedReaderAndWriterDemo.java")));
        
        //写入
        BufferedWriter bw = 
                new BufferedWriter(
                        new FileWriter(
                                new File("dir/这是使用了新方法读取的文件.txt")));
        //读取: readLine(); -->读取一行字符串
        //1.br.readLine(); --> 循环读取 
        // null空值-->没有开辟内存空间
        //循环读取数据 --> 数据写出去? -->参数是XXX类型     
        String content = null;
        //ps:若使用readLine方式读取数据,首先会认为读取到
或
作为一行的纪委,然后若读取到文件的末尾会返回null
        //   readLine不会读取换行符(回车)
        while((content = br.readLine())!=null) {
            //写出去
            bw.write(content);
            //在写出数据时,需要手动添加换行符,保证数据格式的正确
            bw.newLine();
        }
       
        bw.flush();
        System.out.println("写完了!!!");
        bw.close();
        br.close();
        
        
    }
    
}


总结:
字节和字符缓冲输入输出流 自带缓冲区 默认大小是8192 --> 1024*8
字节的缓冲流操作方式没有特殊方法可以完全参数父类流的使用方法
字符的缓冲流操作方法有特殊方法,并且建议使用
读取数据时使用readLine方法 --> 读取一个行数据返回值是String类型
既然使用readLine读取数据那么就需要配合使用newLine这个方法
为什么?因为readLine不能读取换行符号,所以为了保证数据的完成性需要添加换行符即newLine方法


需求: 转换流的,可以设置当前文件的字符编码 转换流默认就是字符流的形式,所以我们可以使用缓冲流包装这个转换流
ps:包装流的形式
看BufferedReaderAndWriterDemo2类

/**
 * 
 */
package com.qfedu.Day21.IO.BufferedReaderAndWriter;

import java.io.*;

/**
 * Description: 字符缓冲输入输出流<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:BufferedReaderAndWriterDemo.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class BufferedReaderAndWriterDemo2 {
    public static void main(String[] args) throws Exception {
        //指定读取文件的字符编码和写出文件的字符编码并且要求使用字符缓冲流的形式完成
        //构建数据
        File src = new File("dir/这是使用了新方法读取的文件.txt");
        File des = new File("dir/使用了缓冲流的形式完成的文件.txt");
        
        ReaderAndWriterNew(src,des,"GBK","UTF-8");  //新读写方式
        

    }
    /**
     * 使用缓冲流的形式完成指定编码文件的读写操作
     * @param src 源文件
     * @param des 目标文件(写入的位置)
     * @param srcCharSetName 源文件的编码
     * @param desCharSetName 目标文件的编码
     * @throws Exception  抛出所有IO异常
     */

    public static void ReaderAndWriterNew(File src,File des,String srcCharSetName,String  desCharSetName) throws Exception {
        /*
         * ps写流的步骤:
                  1.创建流对象(确定流的流向和数据类型)
                  2.循环读取文件中的数据  --> 定义一个变量来获取实际读取的长度
                                判断是否读取到文件的末尾-1
                                 如果没有 将数据写出去
                  3.关闭流        
          通过BufferedReader对 传入参数的流进行一次包装,让当前流具备了缓冲流,从而提高了流的流速
             缓冲流也称之为包装流    
             流式可以嵌套流对象的
             InputStream is = new FileInputStream();
             InputStreamReader isr = new InputStreamReader(new FileInputStream());
             BufferedReader br  = 
                new BufferedReader(
                        new InputStreamReader(
                                new FileInputStream(src), srcCharSetName));                
         */
        //读取
        BufferedReader br  = 
                new BufferedReader(
                        new InputStreamReader(
                                new FileInputStream(src), srcCharSetName));
        
        //写入
        BufferedWriter bw  = 
                new BufferedWriter(
                        new OutputStreamWriter(
                                new FileOutputStream(des),desCharSetName));
    
        //读取: readLine(); -->读取一行字符串
        //1.br.readLine(); --> 循环读取 
        // null空值-->没有开辟内存空间
        //循环读取数据 --> 数据写出去? -->参数是XXX类型     
        String content = null;
        //ps:若使用readLine方式读取数据,首先会认为读取到
或
作为一行的纪委,然后若读取到文件的末尾会返回null
        //   readLine不会读取换行符(回车)
        while((content = br.readLine())!=null) {
            //写出去
            bw.write(content);
            //在写出数据时,需要手动添加换行符,保证数据格式的正确
            bw.newLine();
        }
       
        bw.flush();
        System.out.println("写完了!!!");
        bw.close();
        br.close();
        
        
    }
    
}


属性文件Properties
Properties 继承于 Hashtable资源文件
Hashtable是Map的实现了 Map 键值对形式 key -- value
key保证唯一 value可以不唯一 取出键值对最好的方式 通过key 来获取
Hashtable和HashMap区别
Hashtable是线程安全的,效率低
HashMap线程不安全的,效率高
若是在多线程并发访问的前提下是否要使用HashTable?
肯定不是的,因为Collections工具类型中提供了将HashMap转换为线程安全的方法
Hashtable的使用和HashMap的使用是基本相同

Properties 关系 存储信息 也是以一种键值对的形式存储的
ps:传输数据数据时,有一种轻量级的传输方式
XML --> 对于web即可以作为文件的配置,还可以作为一种数据的传输个是 --->如何书写为了以后配置hadoop环境
Json --> 对于web是一种数据传输形式 --->是一个典型的键值对形式
Properties --> 既可以作为数据传输也可以作为一种文件配置 --> 作为配置文件居多

需求:如何将数据吸入到Properties文件中,然就在将文件读取回来
写JDBC --> 通过程序 对数据库进行操作
配置一个文件用来存储数据的的用户名,密码和驱动
是可以完全程序中的,但是修改起来比较麻烦而且不易于维护
提供一种文件这个文件具备一种键值对的形式 --> Properties,此时就便于维护了
模拟过程
出现如下信息在文件中:
com.qfedu.user = "张三";;
com.qfedu.pwd = "123";
com.qfedu.driver = "com.mysql.driver";
已经完成了如何通过程序将Properties对象转换为文件
若向当前对象中存储数据 setProperty(key, value);
若将当前对象写成文件store(字节流对象, 注释(String形式));
Properties文件的编码时ISO-8859-1是不支持中文的,建议不要写汉字

将Properties中的数据读取回来
1.先创建一个Properties对象
load(字节输入流) 加载properties文件
2.获取文件中对应的属性值
getProperty(对应的key)

/**
 * 
 */
package com.qfedu.Day21.IO.Properties;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; 

/**
 * Description: Properties文件的写入<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:PropertiesDemo.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class PropertiesDemo {
    public static void main(String[] args)throws Exception {
        //第二种写法 使用字符缓冲流获取控制台数据
        BufferedReader br = 
                new BufferedReader(
                        new InputStreamReader(System.in));
        //此时写出的流对象所创建的文件必须后缀名是properties,这样才能创建一个Properties文件
        BufferedWriter bw = 
                new BufferedWriter(
                        new OutputStreamWriter(
                                new FileOutputStream("dir/config.properties")));
        //1.需要创建Properties对象-->util包下的
        Properties p = new Properties();
        //做一个循环读取将数据写到文件汇总
        while(true) {
            System.out.println("请输入key:");
            String key = br.readLine();
            
            //若当前获取key值为Over时,就完成整个输出
            if("over".equals(key)) {
                break;
            }
            
            System.out.println("请输入value:");
            String value = br.readLine();
            
            //以键值对的形式存储数据到Properties文件中
            //此时只是将数据写入到了Properties所创建的对象中
            p.setProperty(key, value);
            
        }
        
        
        //将Properties对象写成文件
        /*
         * 若将Properties对象写文件需要使用下面的方法
         * 第一个参数 是一个字节输出流
         * 第二个参数 当前文件的注释
         * 在properties文件中以#开头的就是注释
         */
        p.store(bw, "我是注释");
        
        

    }

}

/**
 * 
 */
package com.qfedu.Day21.IO.Properties;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

/**
 * Description: 工具类<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:PropertiesUtil.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class PropertiesUtil {
     //工具类中提供的都是静态方法
     //不能允许外部对当前类创建对象
    private PropertiesUtil() {
        
    }
    
    //定义一个静态变量获取资源文件对象
    private static Properties p ; 
    
    //类在创建的同时,就像Properties读取进来
    //这是一种方式
    static {
        //静态属性进行初始化
        p = new  Properties();
        
        //进行文件的加载
        //参数是一个字节输入流
        try {
            //这里的异常不要抛出,将当前异常进行抓取
            p.load(new FileInputStream("dir/config.properties"));
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
    //第二种就是使用类的加载器 ClassLoader --> 必须使用反射 暂留
    
    
    //提供一个静态方法,通过对应的key得到对应的value
    public static String getValue(String key) {
        //properties对象如何去除对应的value值
        return p.getProperty(key);
                
    }
 
}

/**
 * 
 */
package com.qfedu.Day21.IO.Properties;

/**
 * Description: 将文件中的内容读取回来<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:Test.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class Test {
    public static void main(String[] args) {
      String user = PropertiesUtil.getValue("com.qfedu.user");
      String pwd = PropertiesUtil.getValue("com.qfedu.pwd");
      String driver = PropertiesUtil.getValue("com.qfedu.drive");
      System.out.println(user + " " + pwd + " " + driver); 
        
    }

}


对象流
流中的数据是对象
ObjectInputStream 对象字节输入流
ObjectOutputStream 对象字节输出流
如何将对象写入到流中生成文件, 将文件中的对象读取到内存中恢复成数据

ObjectInputStream
通过ObjectInputStream流对象将,文件中存储的对象读取到内存中,这个过程叫做反序列化
ps:这个文件必须是通过ObjectOutputSteam这个流对象写出去

构造方法:
ObjectInputStream(InputStream in) 通过字节输入流创建对象流对象
ps:对象流主要操作的是文件,所以参数传入FileInputStream即可

常用方法
void close() 关闭输入流。
Object readObject() 从文件中将对象读取回来。

/**
 * 
 */
package com.qfedu.Day21.IO.ObjectInputAndOutput.Extend;

import java.io.Serializable;

/**
 * Description: 学生类<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:Student.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
//只要类实现了Serializable接口就一定能进行序列化和反序列
public class Student implements Serializable{

    /**
     *就是为了区分JDK版本号 
     */
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private String gender;
    
    
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public Student(String name, int age, String gender) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    //重写toString

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }

}

/**
 * 
 */
package com.qfedu.Day21.IO.ObjectInputAndOutput.Extend;

import java.io.*;
import java.util.*;

/**
 * Description:对象序列化和反序列化<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:Test.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class Test {

    public static void main(String[] args)throws Exception {
        //创建一个集合存储多个对象
        List<Student> list = new ArrayList<>();
        //向当前集合中存储多个对象
        Collections.addAll(list, new Student("张三",18,"男")
                , new Student("李四",12,"男")
                , new Student("王五",15,"女")
                , new Student("赵六",20,"男"),null);
        //调用序列化方法
        //ObjectInputStreamSerializable(list);
        //反序列化
        List<Student> list1 = ObjectOutputStreamSerializable();
        
        Iterator it = list1.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        

    }
    /**
     * 多个对象的反序列化
     * @throws Exception 异常
     */
    public static List<Student> ObjectOutputStreamSerializable()throws Exception{
        //将当前多个对象进行反序列化 读取回来  -->多个对象,可定需要使用循环,循环停止的条件是什么,如何看到每一个对象中的值
        //只能能完成循环读取,出现异常先不管--> EOF
        ObjectInputStream ois = new  ObjectInputStream(new FileInputStream("dirs/多个对象的序列化"));
        //反序列化就是将文件中的对象读取回来
        //判断一个对象是否存在 --> 判断当前对象地址是够为null
        Object obj = null;
        /*
         * readObject读取文件中的对象,若达到流的末尾(文件末尾) 会返回EOFException
         * 正常判断文件的末尾其实就是读取到最后一个对象是地址是null证明你没有数据了
         * 此时即可以达到避免EOFException,也可以达到读取文件对象的最后一个
         * 所以,若需要对多个对象进行序列化时,习惯将最后一位存为null表示文件的末尾
         */
        List<Student> list = new  ArrayList<>();
        while((obj = ois.readObject()) != null) {
            //System.out.println(obj);
            //readObject的返回值类型是Object,此时需要进行强制类型操作
            //list.add(obj);
            Student stu = (Student)obj; 
            list.add(stu);
                
        }
        return  list;
    }
    /**
     * 多个对象序列化方法
     * @param list  集合中存储多个对象
     * @throws Exception  异常
     */
    public static void ObjectInputStreamSerializable(List<Student> list)throws Exception {
        //创建流对象进行序列化操作ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dirs/多个对象的序列化"));
        //将集合中所有的对象进行序列操作
        //将集合中的对象取出来
        for(Student stu : list) {
            oos.writeObject(stu);
        }
        System.out.println("多个对象序列化完成!!!!");
        oos.flush();
        oos.close();
    }
    
}
/**
 * 
 */
package com.qfedu.Day21.IO.ObjectInputAndOutput.Extend;

import java.io.*;
import java.util.*;

/**
 * Description:系统对象序列化和反序列化<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:Test.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class Test2 {

    public static void main(String[] args)throws Exception {
        //创建一个集合存储多个对象 
        //ArrayList是一个系统类并且实现了Serializable接口
        ArrayList<Student> list = new ArrayList<>();
        //向当前集合中存储多个对象
        Collections.addAll(list
                , new Student("张三",18,"男")
                , new Student("李四",12,"男")
                , new Student("王五",15,"女")
                , new Student("赵六",20,"男"));
        //序列化
        ObjectOutputStream oos  = new ObjectOutputStream(new FileOutputStream("dirs/系统对象序列化"));
        //简介达成多个对象序列化
        oos.writeObject(list);
        oos.flush();
        System.out.println("写完了!");
        
        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dirs/系统对象序列化"));
        Object obj = ois.readObject(); //Object类型
        //ArrayList<Student> list1 = (ArrayList<Student>)obj;
        System.out.println(obj);
    
        }

}

ObjectOutputStream
通过ObjectOutputStream流对象,将对象通过流的形式固化成文件,这个过程叫做序列
ps:若通过ObjectOutputStream将对象固化文件,那么必须通过ObjectInputStream才能将对象恢复

构造方法:
ObjectOutputStream(OutputStream out) 通过字节输入流对象创建对象流对象。
ps:对象流主要操作的是文件,所以参数传入FileOutputStream即可

常用方法:
void close() 关闭流。
void writeObject(Object obj)将当前对象写入到流中并固化成文件

对象的序列化和反序列化

对象的序列化就是将对象固化成文件的过程使用的流:ObjectOutputStream

对象的反序列化就是将固化文件中的对象在读取到内存中:ObjectInputStream

看ObjectInputAndOutput包 --->单个对象存储到序列化文件中

扩展:
多个对象的的序列化和反序列化
看ObjectInputAndOutput.Extend包

只要系统类实现了Serializable那么都可以进行序列化和反序列化

/**
 * 
 */
package com.qfedu.Day21.IO.ObjectInputAndOutput;

import java.io.Serializable;

/**
 * Description: 学生类<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:Student.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
//只要类实现了Serializable接口就一定能进行序列化和反序列
public class Student implements Serializable{

    /**
     *就是为了区分JDK版本号 
     */
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private String gender;
    
    
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public Student(String name, int age, String gender) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    //重写toString

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }

}

/**
 * 
 */
package com.qfedu.Day21.IO.ObjectInputAndOutput;

import java.io.*;

/**
 * Description: 对象的序列化和反序列化<br/>
 * Copyright (c) , 2018, JK <br/>
 * This program is protected by copyright laws. <br/>
 * Program Name:ObjectInputAndOutputDemo.java <br/>
 * 
 * @author 千锋智哥
 * @version : 1.0
 */
public class ObjectInputAndOutputDemo {
    public static void main(String[] args) throws Exception {
        //ObjectOutputStreamSerializable();
     
        //创建方法快捷方式 alt+shift+m --> 一个是名字,一个是修饰符
        ObjectInputStreamSerializable();
        
        
        
        
    }

    /**
     * 对象的反序列化操作
     * @throws Exception序列化异常,文件找不到异常,IO异常
     * 
     */
    public static void ObjectInputStreamSerializable()throws Exception {
        //反序列化 -->将文件中存储对象读取回来
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dir/序列化文件.txt"));
        //如何将对象反序列化出来 -->将当前对象从文件中读取出来
        //返回值是一个Object
        Object obj = ois.readObject();
        System.out.println(obj);
    }

    /**
     * 实现了对象的序列化
     * @throws Exception 序列化异常,文件找不到异常,IO异常
     * 
     */
    public static void ObjectOutputStreamSerializable() throws Exception {
        //自定义类对象的序列化操作
        Student stu= new Student("成龙", 61, "男");
        //1.将当前对象进行序列化操作
        //序列化操作就是将当前对象固化成文件
        //就需要将当前对象写的入到文件中
        //序列化文件不是一个可读文件(不是人类可读),所以序列化文件一般是不适用后缀名
        //只有通过反序列化的方式才能读取文件中的内容
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dir/序列化文件.txt"));
       //2. 将当前对象进行序列化(将当前对象写入到文件中)
        //只要对对象进行序列化或反序列化操作,那么当前对象必须是实现Serializable接口
        //若没有实现会抛出异常
        oos.writeObject(stu);
        oos.flush();
        System.out.println("写完了");
        oos.close();
    }

}

总结:
InputStream 和 OutputStream 字节输入输出流
FileInputStream 和 FileOutputStream 文件字节输入输出流
System.in 和 System.out 标准输入输出流
System.out的实现类是PrintStream 字节打印流
ObjectInputStream 和 ObjectOutputStream 对象字节输出输出流
BufferedInputStream 和 BufferedOutputStream 字节缓冲输入输出流

Reader 和 Writer 字符输出输出流
FileReader 和 FileWriter 文件字符输出输出流
InputStreamReader 字节转换字符流 和 OutputStreamWriter 字符转换字节流
BufferedReader 和 BufferWriter 字符缓冲输入输出流

内存流;
ByteArrayInputStream 和 ByteArrayOutputStream 字节数组内存输入输出流
CharArrayReader 和 CharArrayWriter 字符数组内存输入输出流
StringReader 和 StringWriter 字符串内存输入输出流

除了对象流之外:
确定流的流向,知道流中的数据是什么类型
从文件到内存(读) 从内存到文件(写) --> byte char
定义变量获取实际读取的长度
循环读取调用read方法判断是否是-1,若是就是读取到文件的末尾,不是就是实际长度
将数组存储的数据writer(数组,从数组开始的位置,实际长度)文件中
输出流对象.flush();
输出流对象.close();
输入流对象.close();
特殊的是转换流 -->指定读取和写出文件的编码 --> 读错了写永远都不对

对象类是一个特殊的流
将对象写入(固化)到文件中的过程,序列化-->需要使用ObjectOutputStream这个流
将文件中的对象读取到内存中的过程,反序列化 -->需要使用ObjectInputStream这个流
若需要序列化和反序列化那么当前对象所对象的类必须实现Serializable接口

知识点:
线程(两个部分,如何使用线程 应用部分多线程并发访问临界资源,锁,生产者和消费者模式有序的交替执行,双重检锁机制,死锁(了解),线程声明周期图)
线程中发生任何事情(打印)都是对的,线程是不可控(干预)
现在电脑没有单片机(单核cpu),所以你的打印和我的打印可能是不一样,是对的电脑cpu是不一样

TCP/IP ---> 4个版本
UDP ---> 包
反射 --> 类的加载 如何获取Class类型 通过反射获取属性构造方法方法的调用方式, 类的加载ClassLoader






原文地址:https://www.cnblogs.com/lijun199309/p/9551023.html