流:内存与储存设备之间传输数据的通道

输入流:将存储设备中的内容读入到内存

输出流:将内存中的内容写入到存储设备

字节流:以字节为单位,可以读写所有数据

字符流:以字符为单位,可以读写文本数据

节点流:具有实际传输数据的读写功能

过滤流:在节点流的基础之上增强功能

字节流

字节流基类

  1. InputStream字节流输入基类,抽象类是表示字节输入流的所有类的超类.

    // 从输入流中读取数据的下一个字节
    abstract int read()
    // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
    int read(byte[] b)
    // 将输入流中最多 len 个数据字节读入 byte 数组
    int read(byte[] b, int off, int len)
    // 跳过和丢弃此输入流中数据的 n个字节
    long skip(long n)
    // 关闭此输入流并释放与该流关联的所有系统资源
  2. OutputStream字节输出流基类,抽象类是表示输出字节流的所有类的超类.

    // 将 b.length 个字节从指定的 byte 数组写入此输出流
    void write(byte[] b)
    // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
    void write(byte[] b, int off, int len)
    // 将指定的字节写入此输出流
    abstract void write(int b)
    // 关闭此输出流并释放与此流有关的所有系统资源
    void close()
    // 刷新此输出流并强制写出所有缓冲的输出字节
    void flush()

字节文件操作流

FileInputStream

// 构造方法
// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定
FileInputStream(File file)
// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定
FileInputStream(String name)
//基本使用
FileInputStream fis = new FileInputStream("C:\\Users\\1\\Documents\\Test.txt");

//单个字节读取
int data = 0;
while ((data = fis.read()) != -1) {
    System.out.println((char)data);
}

//多个字节读取
byte[] buf = new byte[1024];
int count = 0;
while ((count = fis.read(buf)) != -1) {
    /**
      * 参数1为要显示的数组,这里是buf
      * 参数2为代表数组从什么地方开始显示,这里为下标0的地方开始
      * 参数3为显示几个元素,这里显示count个元素
      */
    System.out.println(new String(buf, 0, count));
}
//一次读取一个字节数组,提高了操作效率,IO流使用完毕一定要关闭
fis.close();
System.out.println("close");

FileOutputStream

//构造方法
// 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file)
// 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file, boolean append)
// 创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(String name)
// 创建一个向具有指定name的文件中写入数据的输出文件流
FileOutputStream(String name, boolean append)
//基本使用
OutputStream fos = new FileOutputStream(new File("test.txt"));
// 写出数据
fos.write(69);//这里插入的是对应的ascii表的对应编码
fos.write('a');
fos.write('b');
// 关闭IO流
fos.close();
// 内容追加写入
OutputStream fos = new FileOutputStream("test.txt", true);
// 输出换行符
fos.write("\r\n".getBytes());
// 输出追加内容
fos.write("hello".getBytes());
// 关闭IO流
fos.close();
//输出的目的地文件不存在,则会自动创建,不指定盘符的话,默认创建在项目目录下;输出换行符时一定要写\r\n不能只写\n,因为不同文本编辑器对换行符的识别存在差异性。

学完上边这些,下面实现一个复制操作

//文件字节输入流
FileInputStream fis = new FileInputStream("C:\\Users\\1\\Pictures\\o_201106013133212.jpg");

//文件字节输出流
FileOutputStream fos = new FileOutputStream("C:\\Users\\1\\Pictures\\cpoy.jpg");

//复制
byte[] buf = new byte[1024];
int count = 0;
while ((count = fis.read(buf)) != -1){
    fos.write(buf,0,count);
}

//记得关闭
fis.close();
fos.close();

字节缓存流

BufferedInputStream

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\1\\Documents\\Test.txt"));

//读取
int data = 0;
while ((data = bis.read()) != -1){
    System.out.print((char) data);
}

//读取
byte[] data = new byte[1024];
int count = 0;
while ((count = bis.read(data)) != -1) {
    System.out.println(new String(data,0,count));
}

bis.close();

BufferedOutputStream

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\1\\Documents\\TestBuf.txt"));

for (int i = 0; i < 10; i++) {
    bos.write("hello world\r\n".getBytes());//先写入缓冲区
    bos.flush();//刷新到硬盘
}

bos.close();//这里执行close会执行flush

对象流

使用流传输对象的过程称之为序列化、反序列化.

需要序列化的对象必须实现Serializable接口,才可以被序列化.

序列化

序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化,它将流转换为对象,这两个过程结合起来,可以轻松的存储和传输数据.

ObjectOutputStream

OutputStream out = new FileOutputStream("C:\\Users\\1\\Documents\\stu.bin");
ObjectOutputStream oos = new ObjectOutputStream(out);

//序列化(写入操作)
Student stu = new Student("saber",20);
oos.writeObject(stu);

//关闭
oos.close();

ObjectInputStream

InputStream in = new FileInputStream("C:\\Users\\1\\Documents\\stu.bin");
ObjectInputStream ois = new ObjectInputStream(in);

//反序列化(读取)
Student stu = (Student) ois.readObject();
Student stu2 = (Student) ois.readObject();//如果重复读取 会报EOFException的错误
System.out.println(stu);

ois.close();

使用注意

  1. 序列化类必须要实现Serializable接口
  2. 序列化类中的对象属性也必须实现Serializable接口
  3. 序列化版本ID,必须保证序列化的类和反序列化的类是同一个类
  4. 使用transient修饰的属性将不参与序列化
  5. 静态属性不会被序列化
  6. 序列化多个对象可以借助集合实现

字符流

常见字符编码

编码
ISO-8859-1 收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号
UTF-8 针对Unicode码表的可变长度字符编码
GB2312 简体中文
GBK 简体中文、扩充
BIG5 中国台湾、繁体中文

注意:当编码方式和解码方式不一样时,会出现乱码

字符流基类

参考

文章1:https://blog.csdn.net/qq_33642117/article/details/52074796

文章2:https://baijiahao.baidu.com/s?id=1633305649182361563