IO流

IO流

第一章 IO的概述

1.1 什么是IO

当你的电脑插上U盘时可以传输数据,我们把这种传输可以看做是一种数据的流动,按照流动的方向,以内存为基准分为 【输入input】和【输出output】即流向内存是输入流,流出内存是输出流

Java中的 I/O流操作主要是是使用 【Java.io】包下的内容进行输入、输出的操作,输入也叫做读取数据输出也叫做写出数据

1.2 IO 的分类

根据数据的流向分为【输入流】和【输出流】

  • 输入流:把数据从其他设备读取到内存中的流
  • 输出流: 把数据从内存中写出到其他设备上的流

根据数据的类型分为【字节流】和【字符流】

  • 字节流: 以字节为单位 读写数据的流
  • 字符流:以字符为单位 读写数据的流

1.3 顶级的父类

输入流 输出流
字节流 字节输入流
InputStream
字节输出流
OutputStream
字符流 字符输入流
Reader
字符输出流
Writer

第二章 字节流

2.1 字节输出流【OutputStream】 写入信息

Java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写到目的地,他定义了字节输出流的基本共性功能方法

  • public void close()】 关闭输出流并释放与此流相关的任何系统资源

  • public void flush()】 刷新此输出流并强制任何缓冲的输出字节被写出

  • public void write(byte [] b)】 将b.length 字节从指定的字节数组写入此输出流

  • public void write(byte[] b, int off ,int len)】 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流

    int off: 表示开始索引

    int len :表示 写几个字节

  • public abstract void write(int b)】 将指定的字节输出流

小贴士:

close 方法当完成流的操作时,必须调用此方法,释放系统资源

​ 【write(byte [] b)】方法和【write(byte[] b, int off ,int len)】方法可以一次写多个字节

​ 如果写的第一个字节是正数(0-127)那么显示的是时候会查询ASCII表

​ 如果写的第一个字节是负数,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询默认码表(GBK)

2.2 文件字节输出流【FileOutputStream】

【Java.io.FileOutputStream】继承自OutputStream

作用:把内存中的数据写入到硬盘的文件中

构造方法:

  • 【public FileOutputStream(String name)】 创建一个向具有指定名称的文件中写入数据的输出文件流
  • 【public FileOutputStream(File file)】 创建一个指定File对象的表示文件中的写入数据的文件是输出流

参数:

​ String name:目的地个文件的路径

​ File file: 目的地是一个文件

构造方法的作用

  • 创建一个FileOutputStream的对象
  • 会根据构造方法中传递的文件/或者文件路径,创建一个空的文件
  • 会把FileOutputStream指向创建好的文件

代码示例:

package com.io;



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * FileOutputStream 文件字节输出流的使用一次写多个字节
 *- 【**public void   write(byte []    b)**】 将b.length  字节从指定的字节数组写入此输出流
 * - 【**public  void  write(byte[]  b, int    off  ,int  len)**】从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
 */
public class OutputStreamDome02 {
    public static void main(String[] args) throws IOException {

//        show02();

        show03();


    }

    /**
     * 一次写入一个字节
     * public void write(int b) throws IOException
     */
    public static void show01() throws IOException{
        FileOutputStream fos=new FileOutputStream("d:\\1.txt");
        fos.write(123);
        fos.close();
    }

    /**
     * 一次写入多个字节
     * public void write(byte b[]) throws IOException
     */
    public static void show02() throws IOException{
        FileOutputStream fos=new FileOutputStream("d:\\1.txt");
        byte[]  bytes=new byte[]{66,67,68,69,70};
        fos.write(bytes);
        fos.close();
    }


    /**
     * 一次写入多个字节
     * public void write(byte b[], int off, int len) throws IOException
     */
    public static void show03() throws IOException{
        FileOutputStream fos=new FileOutputStream("d:\\2.txt");
        byte[]  bytes=new byte[]{66,67,68,69,70};
        fos.write(bytes,1,2);   //写入 CD
        fos.close();
    }
}

2.3 字节输入流【InputStream】读取信息

java.io.InputStream 抽象类表示字节输入流的所有类的超类,可以读取字节信息到 内存中,他定义了字节输入流的基本共性功能方法

  • public void close()】 关闭此输入流并释放,与此相关的任何系统资源
  • public abstract int read()】 从输入流读取数据的下一个字节
  • pubic int read(byte[] b)】从输入流中读取一些字节数,并将它们存储到字节数组中

小贴士

【close】方法当完成流的操作时,必须调用此方法,释放系统资源

2.4 FileInputStream类

java.io.FileInputStream 类是文件输入流,从文件中读取字节 继承自InputStream

构造方法:

  • public FileInputStream(File file)】 通过打开与实际文件的连接来创建一个FileInputStream,改文件由系统中的File对象 file 命名
  • public FileInputStream(String name)】 通过打开与实际文件的连接来创建一个FileInputStream,改文件由系统中的路径名 name 命名

String】类的构造方法:

  • String(byte[] bytes)】把字节数组转换为字符串
  • String(byte[] bytes, int offset, int length)】 把字节数组的一部分转换为字符串, offset表示数组的开始索引,length表示转换的字节个数

示例代码:

package com.io;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * FileInputStream 文件字节输入流的使用
 *
 */
public class InputStreamDome01 {
    public static void main(String[] args) throws IOException {
//         show01();
        show02();

    }

    /**
     * 一次读取两个字节的代码示例
     *
     * @throws IOException
     */
    public  static  void show01()throws IOException {
        FileInputStream fis=new FileInputStream("a.txt");
        byte[]  bytes=new byte[2];
        int read = fis.read(bytes);
        System.out.println(read);  //输出2
        System.out.println(new String(bytes)); //输出aa
    }

    /**
     * 一次读取多个字节的代码示例
     * @throws IOException
     */
    public  static  void show02()throws IOException {
        FileInputStream fis=new FileInputStream("a.txt");
        byte[]  bytes=new byte[1024];
        int len=0;
        while((len=fis.read(bytes))!=-1){
            //使用String(byte[]  bytes, int  offset, int  length)构造方法转换
            System.out.println(new String(bytes,0,len)); //输出aaaaaaaabbbbbcccccccc
        }
    }
}

练习 文件复制

package com.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 文件复制
 * 1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
 * 2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
 * 3.使用字节输入流对象的read方法读取文件
 * 4. 使用字节输出流的方法write方法把读取到的文件内容写入到目的地的文件中
 * 5.关闭连接释放资源
 */
public class FileCopy {
    public static void main(String[] args) throws IOException {
            fileCopy();
    }


    public static void fileCopy() throws IOException {
       //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream inputStream=new FileInputStream("D:\\Typora\\java文件\\Java基础\\File和IO流\\IO流.assets\\1637256557651.png");
       //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream outputStream=new FileOutputStream("e:\\1637256557651.png");
       //3.使用字节输入流对象的read方法读取文件
//        int len=0;
//        while((len = inputStream.read())!=-1){
//            //4. 使用字节输出流的方法write方法把读取到的文件内容写入到目的地的文件中
//            outputStream.write(len);
//        }

        //使用数组缓冲读取多个字节,写入多个字节
        byte[]  bytes=new byte[1024];
        //使用字节输入流对象的read方法读取文件
        int  len =0;
        while((len = inputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }

       //5.关闭连接释放资源(先关写的流,再关读的流,因为写完了肯定读完了)
        outputStream.close();
        inputStream.close();
    }
}

第三章 字符流

由于字节流读取中文时会出现乱码的问题,所以引入了字符流

3.1 字符输入流【Reader】

java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中,定义了字符输入流的基本共性功能的方法

  • public void close()】 关闭此流并释放与此流相关的任何系统资源
  • public int read()】 从输入流读取一个字符
  • public int reader(char[] cbuf)】 从输入流中读取多个字符,并将它们存储到字符数组中

3.2 FileReader类

【java.io.FileReader】继承自 InputStreamReader ,【InputStreamReader】类继承自 Reader

【FileReader extends InputStreamReader】 , 【InputStreamReader extends Reader】

构造方法

  • FileReader (File file)】 创建一个新的FileReader对象,给定要读取的file对象
  • FileReader(String filename)】 创建一个新的FileReader, 给定要读取的文件的名称

当创建一个流对象时,必须传入一个文件路径,类似于FileInputStream

代码示例

package com.io.reader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Dome01 {
    public static void main(String[] args) throws IOException {
            show02();
    }

    /**
     * 读取单个字节
     * public  int  read()方法的使用
     */
    public static void show01() throws IOException {
        //创建一个FileReader对象,构造方法中的绑定读取的数据源
        FileReader   fileReader=new FileReader("a.txt");
        int len=0;
        while((len = fileReader.read())!=-1){
            System.out.println((char)len);
        }
        fileReader.close();
    }


    /**
     * 读取多个字节
     * public  int  reader(char[]  cbuf)方法的使用
     */
    public static void show02() throws IOException {
        //创建一个FileReader对象,构造方法中的绑定读取的数据源
        FileReader   fileReader=new FileReader("a.txt");
        char[] chars=new char[1024];
        int len=0;
        while((len = fileReader.read(chars))!=-1){
            //输出 aaaaaaaabbbbbcccccccc
            System.out.println(new String(chars,0,len));
        }
        fileReader.close();
    }
}

3.3 字符输出流(Writer)

【java.io.Writer】抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地,他定义了字符输出流的基本的共性功能方法

  • public void write(int c)】 写入单个字符
  • public void write(char[] chars)】写入字符数组
  • public void write(char[] chars, int off, int len )】写入字符数组的某一部分,off表示数组开始的位置索引,len表示写入的字符个数
  • public void write(String str)】 写入字符串
  • public void write(String str , int off,int len)】 写入字符串的某一部分,off表示字符串开始的索引位置,len表示写入的字符个数
  • public void flush()】 刷新该流的缓冲
  • public void close()】 关闭此流,但是需要先刷新它

3.4 FileWriter 类

java.io.FileWriter】 extends OutputStreamWriter extends Writer

构造方法

  • FileWriter(File file)】 根据指定的File对象构造一个FileWriter对象
  • FileWriter(String fileName)】 根据给定的文件名构造一个FileWriter对象

小贴士

1. 虽然参数为int类型的四个字节,但是只会保留一个字符的信息写出
2. 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中

示例代码

package com.io.readerandwriter;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * FileWriter对象的使用
 */
public class Dome01Writer {
    public static void main(String[] args) throws IOException {
            show01();
    }

    /**
     *写入单个字符
     * public  int  read()方法的使用
     */
    public static void show01() throws IOException {
        //创建一个FFileWriter对象,构造方法中的绑定写入数据的目的地
        FileWriter fileWriter=new FileWriter("a.txt");
        fileWriter.write(97);
        fileWriter.flush();
        fileWriter.close();
    }


//    /**
//     * 读取多个字符
//     * public  int  reader(char[]  cbuf)方法的使用
//     */
//    public static void show02() throws IOException {
//        //创建一个FileReader对象,构造方法中的绑定读取的数据源
//        FileReader   fileReader=new FileReader("a.txt");
//        char[] chars=new char[1024];
//        int len=0;
//        while((len = fileReader.read(chars))!=-1){
//            //输出 aaaaaaaabbbbbcccccccc
//            System.out.println(new String(chars,0,len));
//        }
//        fileReader.close();
//    }
}

关闭和刷新

​ 因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中,但是关闭流对象,是无法继续写出数据的,如果我们既想写出数据又想使用流就需要flush方法了

  • flush 刷新缓冲区,流对象可以继续使用
  • close 先刷新缓冲区,然后释放资源,流对象不可以再被使用

续写和换行

1. 续写

构造方法

  • FileWriter(String fileName,boolean append)
  • FileWriter(File file, boolean append)

参数:

String fileName ,File file:写入数据的目的地

​ **boolean append ** 续写开关,true不会创建新的文件覆盖原文件,可以续写,false 创建新的文件覆盖原文件

2. 换行

​ 换行符号: 【Windows \r\n】、 【Linux /n】、【 mac /r】

第四章 io流中的异常处理

JDK9和JDK7中的异常处理新特性

代码示例:

package com.ioexception;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 文件复制
 * 1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
 * 2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
 * 3.使用字节输入流对象的read方法读取文件
 * 4. 使用字节输出流的方法write方法把读取到的文件内容写入到目的地的文件中
 * 5.关闭连接释放资源
 */
public class FileCopyException {
    public static void main(String[] args) {
            fileCopy();
    }

    /**
     * jdk7新特性异常处理
      */    
    public static void fileCopy()  {
        try( //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
            FileInputStream inputStream=new FileInputStream("D:\\Typora\\java文件\\Java基础\\File和IO流\\IO流.assets\\1637256557651.png");
             //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
             FileOutputStream outputStream=new FileOutputStream("e:\\1637256557651.png");
            ){
            //使用数组缓冲读取多个字节,写入多个字节
            byte[]  bytes=new byte[1024];
            //使用字节输入流对象的read方法读取文件
            int  len =0;
            while((len = inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    /**
     * jdk9的io流异常处理
     */
    public static void show02() {
        //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream inputStream=new FileInputStream("D:\\Typora\\java文件\\Java基础\\File和IO流\\IO流.assets\\1637256557651.png");
        //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream outputStream=new FileOutputStream("e:\\1637256557651.png");
        try(inputStream;outputStream){
            //使用数组缓冲读取多个字节,写入多个字节
            byte[]  bytes=new byte[1024];
            //使用字节输入流对象的read方法读取文件
            int  len =0;
            while((len = inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

第五章 属性集【Properties】

介绍

java.util.Properties 继承与Hashtable ,表示一个持久的属性集,它使用键值结构存储数据,每个键及其对应的值都是一个字符串,该类被许多java类使用,比如获取系统属性,System.getProperties方法就是获取一个Properties对象。

properties集合是唯一一个和IO流结合的集合,他是一个双列集合,key和value都是字符串

可以使用集合中的方法store ,把集合中的临时数据,持久化写入到硬盘中存储

可以使用集合中的方法load ,把硬盘中保存的文件(键值对),读取到集合中使用

构造方法

  • public Properties()】 创建一个空的属性集合

基本的存储方法

  • public Object setProperties(String key,String value)】 保存一对属性
  • public String getProperties(String key)】 根据键获取此列表对应的属性值
  • public Set stringPropertyNames()】 所有键的名称的集合

5.1 使用Properties集合存储数据

代码示例

package com.properties;

import java.util.Properties;
import java.util.Set;

/**
 * Properties集合的使用
 */
public class Dome01Properties {
    public static void main(String[] args) {
        show01();
    }

    /**
     * 【**public  Object   setProperties(String key,String value)**】   保存一对属性
     * 【**public   String  getProperties(String key)**】 根据键获取此列表对应的属性值
     * 【**public  Set<String>    stringPropertyNames()**】   所有键的名称的集合
     * 方法的使用
     */
    private static void show01() {
        //创建Properties对象
        Properties properties=new Properties();
        properties.setProperty("赵丽颖","168");
        properties.setProperty("迪丽热巴","170");
        properties.setProperty("古力娜扎","190");

        //使用stringPropertyNames方法把properties中的键取出,存储到set集合中
        Set<String> strings = properties.stringPropertyNames();

        //遍历set集合,取出Properties中的属性
        for (String key : strings) {
            System.out.println(properties.getProperty(key));
        }

    }
}

5.2 Properties集合中的方法store

使用方法【void store(Writer writer , String comments)】字符输流方式

代码示例

package com.properties;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

/**
 * Properties集合中的方法store使用
 */
public class Dome02Properties {
    public static void main(String[] args) throws IOException {
        show01();
    }

    /**
     * 可以使用集合中的方法store  ,把集合中的临时数据,持久化写入到硬盘中存储
     *  void  store(OutputStream  out,String  comments)
     *  void  store(Writer  writer ,  String  comments)
     *  参数:
     *         OutputStream  out:字节输出流,不能写入中文
     *         Writer  writer:字符输出流,可以写中文
     *         String  comments:注释,用来解释说明保存的文件是来做什么的,
     *         不能使用中文,会产生乱码,默认使用的是Unicode编码,一般使用“”空字符串
     *
     * 方法的使用
     */
    private static void show01() throws IOException {
        //创建Properties对象
        Properties properties=new Properties();
        properties.setProperty("赵丽颖","168");
        properties.setProperty("迪丽热巴","170");
        properties.setProperty("古力娜扎","190");

        //创建字符输出流对象,构造方法中绑定要输入的目的地
        FileWriter writer=new FileWriter("a.txt");

        //使用Properties集合中的方法store 把集合中的临时数据,持久化写入到硬盘中存储
        properties.store(writer,"save  data");
        writer.close();

    }
}

运行结果

1637476874961

使用【void store(OutputStream out,String comments)】字节输出流方式

代码示例

package com.properties;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

/**
 * Properties集合中的方法store使用
 */
public class Dome03Properties {
    public static void main(String[] args) throws IOException {
        show01();
    }

    /**
     * 可以使用集合中的方法store  ,把集合中的临时数据,持久化写入到硬盘中存储
     *  void  store(OutputStream  out,String  comments)
     *  void  store(Writer  writer ,  String  comments)
     *  参数:
     *         OutputStream  out:字节输出流,不能写入中文
     *         Writer  writer:字符输出流,可以写中文
     *         String  comments:注释,用来解释说明保存的文件是来做什么的,
     *         不能使用中文,会产生乱码,默认使用的是Unicode编码,一般使用“”空字符串
     *
     * 方法的使用
     */
    private static void show01() throws IOException {
        //创建Properties对象
        Properties properties=new Properties();
        properties.setProperty("赵丽颖","168");
        properties.setProperty("迪丽热巴","170");
        properties.setProperty("古力娜扎","190");

        //创建字节输出流对象,构造方法中绑定要输入的目的地
        FileOutputStream fileOutputStream=new FileOutputStream("a.txt");

        //使用Properties集合中的方法store 把集合中的临时数据,持久化写入到硬盘中存储
        properties.store(fileOutputStream,"save  data");
        fileOutputStream.close();

    }
}

运行结果

1637477064988

5.3 Properties集合中的方法 load

使用【 void load(Reader reader)】字符流方式

代码示例

package com.properties;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

/**
 * Properties集合中的方法 load  使用
 */
public class Dome04Properties {
    public static void main(String[] args) throws IOException {
        show01();
    }

    /**
     * 可以使用集合中的方法 load  ,把集合中的临时数据,持久化写入到硬盘中存储
     *  void  load(InputStream  inStream)
     *  void  load(Reader  reader)
     *  参数:
     *         InputStream  inStream:字节输入流,不能读取含有中文的键值对
     *         Reader  reader:字符输入流,可以读取含有中文的键值对
     * 注意事项:
     *      1. 存储键值对文件中,键与值默认的连接符号可以使用=,空格(其他符号),
     *      2. 存储键值对文件中,可以使用#注释,被注释的键值对不能被读取
     *      3. 存储键值对文件中,键与值默认都是字符串,不用加引号
     * 方法的使用
     */
    private static void show01() throws IOException {
        //创建Properties对象
        Properties properties=new Properties();

        //使用Properties中的 load 方法读取文件
        properties.load(new FileReader("a.txt"));

        //使用stringPropertyNames方法把properties中的键取出,存储到set集合中
        Set<String> strings = properties.stringPropertyNames();

        //遍历set集合,取出Properties中的属性
        for (String key : strings) {
            System.out.println(key+"="+properties.getProperty(key));
        }

    }
}

运行结果

1637478023280

使用【void load(InputStream inStream)】字节流方式

代码示例

package com.properties;

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

/**
 * Properties集合中的方法 load  使用
 */
public class Dome05Properties {
    public static void main(String[] args) throws IOException {
        show01();
    }

    /**
     * 可以使用集合中的方法 load  ,把集合中的临时数据,持久化写入到硬盘中存储
     *  void  load(InputStream  inStream)
     *  void  load(Reader  reader)
     *  参数:
     *         InputStream  inStream:字节输入流,不能读取含有中文的键值对
     *         Reader  reader:字符输入流,可以读取含有中文的键值对
     * 注意事项:
     *      1. 存储键值对文件中,键与值默认的连接符号可以使用=,空格(其他符号),
     *      2. 存储键值对文件中,可以使用#注释,被注释的键值对不能被读取
     *      3. 存储键值对文件中,键与值默认都是字符串,不用加引号
     * 方法的使用
     */
    private static void show01() throws IOException {
        //创建Properties对象
        Properties properties=new Properties();

        //使用Properties中的 load 方法读取文件
        properties.load(new FileInputStream("a.txt"));

        //使用stringPropertyNames方法把properties中的键取出,存储到set集合中
        Set<String> strings = properties.stringPropertyNames();

        //遍历set集合,取出Properties中的属性
        for (String key : strings) {
            System.out.println(key+"="+properties.getProperty(key));
        }

    }
}

运行结果

1637478132904

第六章 缓冲流

6.1 概述

缓冲流也叫高效流,是对四个基本的流的增强,所以也是四个流,按照数据类型分类

  • 字节缓冲流:BufferedInputStream, BufferedOutputStream
  • 字符缓冲流: BufferedReader, BufferedWriter

原理

​ 创建流对象时,会创建一个内置默认大小的缓冲区数组,通过缓冲区读写,减少系统的IO次数,从而提高读写的效率

6.2 字节缓冲流

构造方法

  • public BufferedInputStream(InputStream in)】 创建一个新的缓冲输入流
  • public BufferedOutputStream(OutputStream out)】 创建一个新的缓冲输出流

6.2.1 字节缓冲输出流【BufferedOutputStream】

代码示例

package com.iobuffered;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 字节缓冲输出流使用案例
 */
public class BufferedOutputStreamDome01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    public static void show01() throws IOException {
        //1.创建一个 FileOutputStream 对象
        FileOutputStream fileOutputStream=new FileOutputStream("a.txt");

        // 2. 创建  BufferedOutputStream 对象  构造方法中传递 FileOutputStream 对象
        BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream);

        // 3.使用 BufferedOutputStream 对象中的 write 方法,将数据写入到文件中
        bufferedOutputStream.write("我把数据写入到了缓冲区中".getBytes());

        //4. 调用 BufferedOutputStream 对象的 flush 方法
        bufferedOutputStream.flush();
        //5. 释放资源
        bufferedOutputStream.close();
    }
}

运行结果

1637479986837

6.2.2 字节缓冲输入流【BufferedInputStream】

代码示例

package com.iobuffered;

import java.io.*;

/**
 * 字节缓冲输入流
 */
public class BufferedInputStreamDome01 {
    public static void main(String[] args) throws IOException {
        show01();
    }


    /**
     * 使用  int  read() 方法
     * @throws IOException
     */
    public static void show01() throws IOException {
        //1.创建一个 FileInputStream 对象
        FileInputStream fileInputStream=new FileInputStream("a.txt");

        // 2. 创建  BufferedInputStream 对象  构造方法中传递 FileOutputStream 对象
        BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);

        // 3.使用 BufferedInputStream 对象中的 read 方法读取文件数据
        int len=0;
        while((len = bufferedInputStream.read())!=-1){
            System.out.println(len);
        }
        //4. 释放资源
        bufferedInputStream.close();
    }


    /**
     * 使用  int  read(byte[] bytes) 方法
     * @throws IOException
     */
    public static void show02() throws IOException {
        //1.创建一个 FileInputStream 对象
        FileInputStream fileInputStream=new FileInputStream("a.txt");

        // 2. 创建  BufferedInputStream 对象  构造方法中传递 FileOutputStream 对象
        BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);

        // 3.使用 BufferedInputStream 对象中的 read 方法读取文件数据
        byte[] bytes=new byte[1024];
        int len=0;
        while((len = bufferedInputStream.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }
        //4. 释放资源
        bufferedInputStream.close();
    }
}

a.txt文件

1637480774031

运行结果

1637480782955

6.3 字符缓冲流

  • public BufferedReader(Reader reader)】 创建一个新的缓冲输入流
  • public BufferedWriter(Writer writer)】 创建一个新缓冲输出流

构造举例代码如下:

        //创建一个新的缓冲输入流
        BufferedReader br=new BufferedReader(new FileReader("a.txt"));

        //创建一个新缓冲输出流
        BufferedWriter bw=new BufferedWriter(new FileWriter("a.txt"));

6.3.1 字符缓冲输出流 【BufferedWriter】

代码示例

package com.iobuffered;

import java.io.*;

public class BufferedWriterDome01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    private static void show01() throws IOException {
        //创建一个新的缓冲输入流
//        BufferedReader br=new BufferedReader(new FileReader("a.txt"));

        //创建一个新缓冲输出流
        BufferedWriter bw=new BufferedWriter(new FileWriter("a.txt"));

        //使用 BufferedWriter 对象中的 write 方法,将数据写入到文件中
        bw.write("使用字符缓冲输出流");
        bw.close();
    }
}

6.3.2 字符缓冲输入流 【BufferedReader】

代码示例

package com.iobuffered;

import java.io.*;

public class BufferedReaderDome01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    /**
     * 使用 BufferedReader 对象中的额readLine 方法每次读取一行数据
     * @throws IOException
     */
    private static void show01() throws IOException {
        //创建一个新的缓冲输入流
        BufferedReader br=new BufferedReader(new FileReader("a.txt"));
        //使用 BufferedReader 对象中的额readLine 方法每次读取一行数据
        String line;
       while((line = br.readLine()) != null){
           System.out.println(line);
       }
        br.close();
    }
}

a.txt文本

1637482389815

运行结果

1637482415799

第七章 转换流

7.1 字符编码和字符集

1637483410851

1637483559418

1637483818511

1637484043465

7.2 编码引出的问题

1637484131836

7.3 InputStreamReader类(读)

1637484448937

代码示例

package com.ioforconversion;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * InputStreamReader 缓冲流的使用
 */
public class DomeInputStreamReader01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    private static void show01() throws IOException {
          //创建一个 OutputStreamWriter 对象
        InputStreamReader inputStreamReader =new InputStreamReader(new FileInputStream("a.txt"),"utf-8" );

        //使用  InputStreamReader 对象中的方法 read  将字符转为字节存储到缓存区中
        int len =0;
        while((len = inputStreamReader.read())!=-1){
            System.out.println((char)len);
        }
        //关闭资源
        inputStreamReader.close();
    }
}

7.4 OutputStreamWriter类(写)

1637485282808

代码示例

package com.ioforconversion;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * OutputStreamWriter 缓冲流的使用
 */
public class DomeOutputStreamWriter01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    private static void show01() throws IOException {
          //创建一个 OutputStreamWriter 对象
        OutputStreamWriter outputStreamWriter=new OutputStreamWriter(new FileOutputStream("a.txt"),"utf-8" );
        
        //使用  OutputStreamWriter 对象中的方法write  将字符转为字节存储到缓存区中
        outputStreamWriter.write("你好");
        
        //刷新
        outputStreamWriter.flush();
        //关闭资源
        outputStreamWriter.close();
    }
}

第八章 序列化和序列化概述

8.1 概述

1637495246785

8.2 ObjectOutputStream类

java.io.ObjectOutputStream 类 将java对象的原始数据写出到文件中,实现对象的持久存储

构造方法

  • 【**public ObjectOutputStream(OutputStream out) **】创建一个指定 **OutputStream ** 的 ObjectOutputStream

代码示例

FileOutputStream  fileOut=new FileOutputStream("a.txt");

ObjectOutputStream  out=new ObjectOutputStream(fileOut);

序列化操作

​ 一个对象想要序列化必须满足两个条件

  • 该类必须实现 【java.io.Serializable】接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或者反序列化,会抛出 NotSerializableException
  • 该类的所有属性必须是可序列化的,如果有一个属性不需要序列化,则该属性必须注明是瞬态的,使用 transient 关键字修饰

代码示例

package com.ioforserialization;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * ObjectOutputStream 序列化流的操作
 */
public class ObjectOutputStreamDome01 {
    public static void main(String[] args) throws IOException {
        show01();
    }

    private static void show01() throws IOException {
        //创建 ObjectOutputStream 对象 构造方法中传递字节输出流
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("person.txt"));

        //使用 ObjectOutputStream 对象中的writeObject 方法,把对象写到文件中
        objectOutputStream.writeObject(new Person("小程",19));
        //释放资源
        objectOutputStream.close();
    }
}

被序列化的类:

package com.ioforserialization;

import java.io.Serializable;

public class Person implements Serializable {
    private String name;

    private int age;

    public  Person(){}

    public Person(String name,int age){
        this.age=age;
        this.name=name;
    }

    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

运行后person.txt文件的内容

�� sr com.ioforserialization.Person�0B[�d�G I ageL namet Ljava/lang/String;xp   t 小程

8.3 ObjectInputStream 类

ObjectInputStream 反序列化流,将之前使用的 ObjectOutputStream序列化的原始数据恢复到对象

反序列化的前提

  • 类必须实现接口 Serializable
  • 必须存在类对应的class文件

构造方法

  • 【**public ObjectInputStream (InputStream in) **】创建指定InputStream 的 ObjectInputStream

反序列化操作

如果能够找到一个对象的class文件,我们就可以进行反序列化操作,调用 **ObjectInputStream ** 读取对象的方法

  • public final Object readObject()】 读取一个对象,该方法会抛出 ClassNotFoundException 异常

代码示例

package com.ioforserialization;

import java.io.*;

/**
 * ObjectInputStream 反序列化流的操作
 */
public class ObjectInputStreamDome01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        show01();
    }

    private static void show01() throws IOException, ClassNotFoundException {
        //创建 ObjectInputStream 对象 构造方法中传递字节输出流
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("person.txt"));

        //使用 ObjectInputStream 对象中的readObject 方法,读取保存对象的文件
        Object o = objectInputStream.readObject();
        //释放资源
        objectInputStream.close();

        //打印读取出来的对象
        System.out.println(o);//Person{name='小程', age=19}
        
        Person person=(Person)o;
        System.out.println("姓名----"+person.getName()+",  年龄---"+person.getAge());
    }
}

注意事项:

static静态关键字,优先非静态加载到内存中,静态优先于对象加载到内存中

​ 被static修饰的成员不能被序列化,序列化的都是对象

transient 关键字,是个瞬态关键字,被它修饰的成员不能被序列化。

8.4 反序列化操作时出现的异常解决

当JVM反序列化时,能找到class文件,但是class文件在序列化之后发生了改变,那么反序列化操作也会失败,抛出一个 InvalidClassException 异常,发生这个异常的原因

  • 该类的序列版本号与从流中读取的类的描述版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参构造方法

Serializable 接口给需要序列化的类提供了一个序列版本号,serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配

解决方案:在类中手动加入序列化版本号【 private static final long serialVersionUID=1l;

代码示例:

package com.ioforserialization;

import java.io.Serializable;

public class Person implements Serializable {

    //手动加入序列号版本
    private static final long serialVersionUID=1l;
    
    private String name;

    private int age;
    
    //添加新的属性,重新编译,仍然可以反序列化,该属性设为默认值
    private String  address;

    public  Person(){}

    public Person(String name,int age){
        this.age=age;
        this.name=name;
    }

    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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

8.5 练习 序列化集合

Person类

package com.listserializable;

import java.io.Serializable;

public class Person implements Serializable {

    //手动加入序列号版本
    private static final long serialVersionUID=1l;
    private String name;

    private int age;

    //添加新的属性,重新编译,仍然可以反序列化,该属性设为默认值
    private String  address;

    public Person(){}

    public Person(String name, int age){
        this.age=age;
        this.name=name;
    }

    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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

ListSerializable类

package com.listserializable;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 序列化集合练习
 */
public class ListSerializable {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        show01();
    }

    private static void show01() throws IOException, ClassNotFoundException {
        //定义一个集合
        List<Person>   list=new ArrayList<>();
        list.add(new Person("小程",19));
        list.add(new Person("小花",17));
        list.add(new Person("小冬",15));
        list.add(new Person("小江",20));

        //创建一个序列化 ObjectOutputStream 对象
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("listperson.txt"));
        //使用 ObjectOutputStream 对象中的writeObject 方法,把对象写到文件中
        objectOutputStream.writeObject(list);


        //创建一个反序列化 ObjectInputStream 对象 构造方法中传递字节输出流
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("listperson.txt"));

       //使用 ObjectInputStream 对象中的readObject 方法,读取保存对象的文件
        List<Person> people = (List<Person>) objectInputStream.readObject();
        //遍历集合
        for (Person person : people) {
            System.out.println(person);
        }

        //释放资源
        objectInputStream.close();
        objectOutputStream.close();
    }
}

运行结果

1637514337745

posted @ 2021-11-22 01:42  闲转  阅读(101)  评论(0)    收藏  举报