IO流的分类、字节流输入流输出流的创建、字节流标准化异处理、字节流文件给复制、缓冲过滤流以及对象过滤流的原理及创建

概念

将数据在JVM和存储设备之间传输

I:input 输入

O:output 输出

  • 用来进行数据传输,相当于管道

流的分类

  1. 从传输方向上看

    • 输入流:存储设备向JVM传输数据

    • 输出流:JVM向存储设备传输数据

  2. 从传输单位上看

    • 字节流:以字节为单位进行数据传输,可以传输任意类型的数据,如视频、图片、音频、文本等

    • 字符流:以字符为单位进行数据传输,只能传输文本类型的数据,如.txt、.java、.html等

  3. 从传输功能上看

    • 节点流:真正具备传输功能的流

    • 过滤流:没有传输功能,作用为给节点流增加附加功能或增强其传输能力

字节流

  • InputStream:字节输入流总父类 抽象父类

  • OutputStream:字节输出流总父类 抽象父类

输入

  • FileInputStream:文件字节输入节点流

创建

FileInputStream fis = new FileInputStream("本地文件路径");
  • 路径的两种书写方式:

    1. 绝对路径:以磁盘为基点的完整路径

      FileInputStream fis = new FileInputStream("E:\\test\\a.txt");
      FileInputStream fis2 = new FileInputStream("e:/test/a.txt");
    2. 相对路径:以当前项目为基点的路径

      FileInputStream fis4 = new FileInputStream("file\\b.txt");
  • 文件路径不正确时,会报出java.io.FileNotFoundException异常

  • 路径必须截至至文件

常用方法

  1. void close():所有流都拥有的方法,关闭链接,释放相关资源

  2. int read():读取一次字节至JVM中,返回值为读取的字节对应的整数值。读取到达末尾返回-1

  3. int read(byte[] ):一次尝试读取指定数组长度的数据至数组中,返回实际读取个数,读取到达末尾返回-1

​
​
import java.io.FileInputStream;
​
public class Test {
    public static void main(String[] args) throws Exception{
        //创建一个字节输入节点流
        FileInputStream fis = new FileInputStream("file\\b.txt");
​
        //读取一个字节
        /*System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
        System.out.println(fis.read());
​
        System.out.println(fis.read());*/
        //利用read()读取文件所有内容
        while(true){
            //接收本次读取结果
            int n= fis.read();
            //判断是否读取结束
            if (n == -1) {
                break;
            }
            //输出查看本次读取内容
            System.out.println((char) n);
        }
​
        /*byte[] bs = new byte[3];
        int n=fis.read(bs);//尝试读取3个字节存放到bs数组中
​
        System.out.println("实际读取个数"+n);
        System.out.println("查看本次读取结果:");
        for (byte b : bs) {
            System.out.print(b+"  ");
        }*/
        //利用read(byte[])读取文件所有内容
        while(true){
            //创建用来接收的数组
            byte[] bs = new byte[3];
            //接收本次读取结果
            int n= fis.read(bs);
            //判断是否读取结束
            if (n == -1) {
                break;
            }
            //遍历数组,查看本次读取结果
            for (byte b : bs) {
                System.out.print(b+"  ");
            }
            System.out.println();
​
        }
​
        //关流
        fis.close();
        System.out.println("程序正常结束");
    }
}
​

输出

  • FileOutputStream:文件字节输出节点流

创建

FileOutputStream  fos=new FileOutputStream("目标文件路径",true|false);
  • true代表数据追加,false代表数据覆盖。默认为false

  • 如果文件不存在则自动创建,无法创建文件夹

常用方法

  1. void flush():所有输出流中都拥有的方法,强制刷新数据缓冲区

  2. void write(int ):一次写入一个字节

  3. void write(byte[] ):一次写入一个数组的数据

package com.bz.test;
​
import java.io.FileOutputStream;
​
/**
 * 往目标文件写入数据
 */
public class OutputStreamTest {
    public static void main(String[] args)throws Exception {
        //创建一个字节输出节点流
        FileOutputStream fos = new FileOutputStream("file/c.txt");
        //一次写入一个字节
        fos.write(65);
        fos.write(66);
        fos.write(67);
        fos.write(68);//ABCD
        fos.write(69);//ABCD
        //一次写入一个字节数组
        String str = "abcdedf";
        //转为数组接收
        byte[] bs = str.getBytes();
        //把bs中的数据全部写进目标文件
        fos.write(bs);
        //关流
        fos.close();
        System.out.println("操作成功!");
    }
}
​

标准异常处理

package com.bz.test;

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

/**
 * 往目标文件写入数据
 */
public class OutputStreamExceptionTest {
    public static void main(String[] args) {
        //创建一个字节输出节点流
        FileOutputStream fos = null;
        try {
            //创建一个字节输出节点流
            fos = new FileOutputStream("file2/c.txt");
            //一次写入一个字节
            fos.write(65);
            fos.write(66);
            fos.write(67);
            fos.write(68);//ABCD
            fos.write(69);//ABCD
            //一次写入一个字节数组
            String str = "abcdedf";
            //转为数组接收
            byte[] bs = str.getBytes();
            //把bs中的数据全部写进目标文件
            fos.write(bs);

            System.out.println("操作成功!");
        } catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读或写失败!");
        } catch (Exception e) {
            System.out.println("未知异常!");
            e.printStackTrace();
        }finally {
            if (fos != null) {//非空判断,防止空指针
                try {  //关流
                    fos.close();
                } catch (IOException e) {
                    System.out.println("关流失败!");
                }
            }
        }
    }
}

  • finally中的内容写法固定(1. 非空判断 2. close关流),为了简化书写,JDK7.0时提供了try-with-sourse自动关流语法

try(
    //流的创建语句
){
    //有可能出现异常的其他代码
}catch(){//异常捕捉
​
}
  • 原理:所有流都默认实现了AutoCloseable接口,该接口中提供了自动关流所需的close()方法

package com.bz.test;
​
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
​
/**
 * 往目标文件写入数据
 */
public class OutputStreamExceptionTest {
    public static void main(String[] args) {
​
        try (
                //创建一个字节输出节点流
                FileOutputStream fos = new FileOutputStream("file2/c.txt");
                ){
            //一次写入一个字节
            fos.write(65);
            fos.write(66);
            fos.write(67);
            fos.write(68);//ABCD
            fos.write(69);//ABCD
            //一次写入一个字节数组
            String str = "abcdedf";
            //转为数组接收
            byte[] bs = str.getBytes();
            //把bs中的数据全部写进目标文件
            fos.write(bs);
​
            System.out.println("操作成功!");
        } catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读或写失败!");
        } catch (Exception e) {
            System.out.println("未知异常!");
            e.printStackTrace();
        }
    }
}

文件复制

  • 原理:让JVM作为数据中转站,先将文件A中的数据读取到JVM中,再把读取的数据写入到文件B

    • 先读后写

package com.bz.test;
​
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
​
public class FileCopyTest {
    public static void main(String[] args) {
        copy1();
        copy2();
    }
    /**
     * 一次复制一个字节
     */
    public static void copy1(){
        try (
                //创建字节输出节点流-复制到的文件路径
                FileOutputStream fos=new FileOutputStream("e:/b.chw");
                //创建字节输入节点流-被复制的文件路径
                FileInputStream fis=new FileInputStream("e:/a.chw")
                ) {
            while (true) {
                //接收本次读取内容
                int n= fis.read();
                //判断读取是否结束
                if (n == -1) {
                    break;
                }
                //将本次读取字节写入目标文件
                fos.write(n);
            }
​
            System.out.println("复制成功!");
​
        } catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读写失败!");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
    }
​
    /**
     * 一次复制一个数组
     */
    public static void copy2(){
        try (
                //创建字节输出节点流-复制到的文件路径
                FileOutputStream fos=new FileOutputStream("e:/c.chw");
                //创建字节输入节点流-被复制的文件路径
                FileInputStream fis=new FileInputStream("e:/a.chw")
        ) {
            while (true) {
               //创建用来接收的数组
                byte bs[] = new byte[1024];
                //接收读取结果-将数据读取到bs中
                int n = fis.read(bs);
                //判断读取是否结束
                if (n == -1) {
                    break;
                }
                //将存放数据的bs写入到目标文件
                fos.write(bs);
            }
​
            System.out.println("复制成功!");
​
        } catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读写失败!");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
​
    }
}
​

缓冲过滤流

  • BufferedInputStream:输入

  • BufferedOutputStream:输出

原理

内置了数据缓冲区,在进行读写操作时,会先将数据存入缓冲区,当缓冲区存满或强制刷新时,才会将内部数据进行下一步传递,以此节省传递频率,提高传输效率

创建

  • 基于节点流

BufferedInputStream bis=new BufferedInputStream(fis节点流对象);//输入
BufferedOutputStream bos=new BufferedOutputStream(fos节点流对象);//输出
/**
     * 一次复制一个字节+缓冲过滤流
     */
    public static void copy3(){
        try (
                //创建字节输出节点流-复制到的文件路径
                FileOutputStream fos=new FileOutputStream("e:/d.chw");
                //创建字节输入节点流-被复制的文件路径
                FileInputStream fis=new FileInputStream("e:/a.chw");
                //添加缓冲过滤流
                BufferedOutputStream bos=new BufferedOutputStream(fos);
                BufferedInputStream bis=new BufferedInputStream(fis)
        ) {
            while (true) {
                //接收本次读取内容
                int n= bis.read();
                //判断读取是否结束
                if (n == -1) {
                    break;
                }
                //将本次读取字节写入目标文件
                bos.write(n);
            }
​
            System.out.println("复制成功!");
​
        } catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读写失败!");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
    }

如果进行手动关流,只需要关闭外层过滤流即可

  • 在对同一个文件进行先写后读操作时,在写入完成之后必须强制刷新缓冲区将数据存入目标文件的时机提前,才能保证读操作的正常进行

    • 强制刷新缓冲区:

      1. bos.flush():直接强刷缓冲区(推荐)

      2. bos.close():直接关流,关流之前会自动调用flush()进行强刷缓冲区

package com.bz.test2;
​
import java.io.*;
​
/**
 * 先写后读
 */
public class Test {
    public static void main(String[] args) {
        try(
               //创建字节输出输入节点流
               FileOutputStream fos=new FileOutputStream("file/b.txt");
               FileInputStream fis=new FileInputStream("file/b.txt");
               //添加缓冲过滤流
               BufferedOutputStream bos=new BufferedOutputStream(fos);
               BufferedInputStream bis=new BufferedInputStream(fis)
                ){
            //往b.txt写入ABCD
            bos.write(65);
            bos.write(66);
            bos.write(67);
            bos.write(68);
            System.out.println("写入成功!");
            //强制刷新缓冲区,将数据提前写入b.txt
            bos.flush();
            //bos.close();
            //从b.txt中读取所有内容
            while(true){
                int n= bis.read();
                if (n == -1) {
                    break;
                }
                System.out.println((char) n);
            }
​
        }catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读写失败!");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
    }
}
​

对象过滤流

  • 附加功能1:读写基本类型

  • 附加功能2:读写引用类型

  • ObjectInputStream:输入流

  • ObjectOutputStream:输出流

读写基本类型

ois.readXxx():读-输入
oos.writeXxx(实参):写-输出
注:Xxx表示的是基本类型,首字母大写
package com.bz.test2;
​
import java.io.*;
​
/**
 * 对象过滤流读写基本类型
 */
public class ObjectTest {
    public static void main(String[] args) {
        try(
                //创建字节输出输入节点流
                FileOutputStream fos=new FileOutputStream("file/b.txt");
                FileInputStream fis=new FileInputStream("file/b.txt");
                //添加对象过滤流
                ObjectOutputStream oos=new ObjectOutputStream(fos);
                ObjectInputStream ois=new ObjectInputStream(fis)
                ){
            //先往b.txt中写入一个double数据
            oos.writeDouble(6.6);
            System.out.println("写入成功!");
            //强刷缓冲区
            oos.flush();
            //再读取b.txt中的数据
            System.out.println(ois.readDouble());
​
        }catch...
    }
}
​
  • 对同一个文件进行先写后读时,仍然需要在写入完成后强刷缓冲区

  • 为了确保数据读写过程中的安全性,在写入时会通过魔数机制对其加密,之后在读取时会再对其解密

读写引用类型

Object  readObject():读-输入  读取到达末尾,抛出EOFException异常
void  writeObject(Object ):写-输出  该方法可以自动强刷缓冲区
  • readObject进行读取结果接收时,如果接收类型为具体引用类型,则需要强转

读写String

​
import java.io.*;
​
/**
 * 对象过滤流读写String类型
 */
public class ObjectTest2 {
    public static void main(String[] args) {
        try(
                //创建字节输出输入节点流
                FileOutputStream fos=new FileOutputStream("file/b.txt");
                FileInputStream fis=new FileInputStream("file/b.txt");
                //添加对象过滤流
                ObjectOutputStream oos=new ObjectOutputStream(fos);
                ObjectInputStream ois=new ObjectInputStream(fis)
                ){
            //先往b.txt中写入一段打油诗
            oos.writeObject("太阳当空照");
            oos.writeObject("花儿对我笑");
            oos.writeObject("小鸟说早早早");
            oos.writeObject("你有病啊起这么早");
            System.out.println("写入成功!");
            //读取文件内容
            while (true) {
                try {
                    String s = (String) ois.readObject();
                    //输出查看
                    System.out.println(s);
                } catch (EOFException e) {
                    //读取结束。跳出循环
                    break;
                }
            }
​
        }catch (FileNotFoundException e) {
            System.out.println("文件路径不正确");
        } catch (IOException e) {
            System.out.println("读写失败!");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
    }
}
​

读写自定义类型

  • 自定义类型必须实现Serializable接口,意味着该类允许被序列化

    • 如果类中有属性也是自定义类型,则该属性类也必须实现Serializable接口,除非其声明了不参与序列化

  • 可以通过在属性声明前添加transient修饰符的方式防止某个属性参与序列化

package com.bz.entity;
​
import java.io.Serializable;
​
public class Student implements Serializable {
    private String name;
    //防止年龄参与序列化
    transient private int age;
    private double score;
    //老师对象属性
    private Teacher tea;
​
    //省略getter、setter、构造、toString()
}
​
package com.bz.entity;
​
import java.io.Serializable;
​
public class Teacher implements Serializable {
​
}
package com.bz.test2;
​
import com.bz.entity.Student;
import com.bz.entity.Teacher;
​
import java.io.*;
​
/**
 * 对象过滤流读写自定义对象类型
 */
public class ObjectTest3 {
    public static void main(String[] args) {
        try(
                //创建字节输出输入节点流
                FileOutputStream fos=new FileOutputStream("file/b.txt");
                FileInputStream fis=new FileInputStream("file/b.txt");
                //添加对象过滤流
                ObjectOutputStream oos=new ObjectOutputStream(fos);
                ObjectInputStream ois=new ObjectInputStream(fis)
                ){
            //创建学生对象
            Student stu = new Student("zhangsan", 18, 90,new Teacher());
            //将学生对象写入b.txt
            oos.writeObject(stu);
            System.out.println("写入成功");
            //读取学生信息
            Student student = (Student) ois.readObject();
            System.out.println(student);
​
        }catch...
    }
}

怎么理解输出语句?

System.out.print()|println();

  1. System是类库中的一个final类

  2. out是System类中的一个静态属性,类型为PrintStream标准输出流类型

  3. print()|println()是PrintStream中的方法,作用为向控制台输出指定内容

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值