1. Io流

流是一组有序的、有起点和终点的字节集合,是对数据传输的总称和抽象。即数据在两设备之间的传输称为流,流的本质是数据传输,数据传输是需要通道的,而IO流就是数据传输的通道。

分类

根据处理数据类型的不同分为字节流和字符流。

根据数据流向的不同分为输入流和输出流。

字符流

InputStreamOutputStream是java中可以按照最小字节单位读取的流,即每次读写一个字节,字节流是直接连接到输入源的流。

  1. **字节输入流InputStream**
  2. InputStream是所有输入字节流的父类,是一个抽象类。
  • ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据
  • PipedInputStream是从与其它线程共用的管道中读取数据
  • ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)

    字节输出流OutputStream

    OutputStream 是所有的输出字节流的父类,它是一个抽象类。

  • ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据

  • PipedOutputStream 是向与其它线程共用的管道中写入数据
  • ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流

字符流

字符流是以字符为单位进行数据处理的IO流。本质其实就是基于字节流读取时,去查找指定的码表。是以Reader和Writer为基础派生的一系列类。

**字符输入流Reader**

Reader 是所有的输入字符流的父类,它是一个抽象类。
  • CharReader、StringReader 是两种基本的介质流,它们从Char 数组、String中读取数据
  • PipedReader 是从与其它线程共用的管道中读取数据
  • BufferedReader 是一个装饰器,它和其子类负责装饰其它Reader 对象。FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号
  • InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流

    字符输出流Writer

    Writer 是所有的输出字符流的父类,它是一个抽象类。

  • CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据

  • PipedWriter 是向与其它线程共用的管道中写入数据
  • BufferedWriter 是一个装饰器为Writer 提供缓冲功能
  • PrintWriter 和PrintStream 功能和使用极其类似
  • OutputStreamWriter 是OutputStream 到Writer 转换的桥梁

字符流和字节流的区别

  • 字节流以字节(8bit)为单位,字符流以字符为单位
  • 字节流能处理所有类型的数据(如图片、.avi等),字符流只能处理纯文本的数据

结论:如果处理纯文本的数据优先考虑字符流,其他情况用字节流。

字符流与字节流转换

InputStreamReader:字节到字符的桥梁

OutputStreamWriter:字符到字节的桥梁

2. File

Files.exists():检测文件路径是否存在。

Files.createFile():创建文件。

Files.createDirectory():创建文件夹。

Files.delete():删除一个文件或目录。

Files.copy():复制文件。

Files.move():移动文件。

Files.size():查看文件个数。

Files.read():读取文件。

Files.write():写入文件。

3. 序列化与反序列

序列化

Java对象转换为字节序列的过程称为对象的序列化,即将对象写入到IO流中。

序列化是为了解决在对象流进行读写操作时所引发的问题。序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。

要对一个对象序列化,这个对象就需实现Serializable接口。序列化只能保存对象的非静态成员变量,而不能保存任何成员方法和静态成员变量,并且保存的只是变量的值,变量的修饰符对序列化没有影响。

序列化

  • 创建 ObjectOutputStream
  • 调用ObjectOutputStream对象的writeObject ()得到序列化对象
package com.lymn.io;

import java.io.*;

public class Person implements Serializable {
    private int age;
    private char sex;
    private String name;
    public Person(int age, char sex, String name) {
        this.age = age;
        this.sex = sex;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", sex=" + sex +
                ", name='" + name + '\'' +
                '}';
    }
    public static void main(String[] args) throws IOException {
        Person p=new Person(22,'男',"小红");
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("D:/ca/person.txt"));
        out.writeObject(p);
    }
}

 sr com.lymn.io.Person匓猴蛅a I ageC sexL namet Ljava/lang/String;xp u7t 灏忕孩

任何用 transient 关键字标明的成员变量,都不会被保存(保密数据、Thread对象或流对象)

反序列化

反序列化就是从 IO 流中恢复对象。

反序列化

  • 创建 ObjectInputStream
  • 调用ObjectInputStream对象的readObject()得到序列化对象
package com.lymn.io;

import java.io.*;

public class Person implements Serializable {
    private int age;
    private char sex;
    private String name;
    public Person(int age, char sex, String name) {
        this.age = age;
        this.sex = sex;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", sex=" + sex +
                ", name='" + name + '\'' +
                '}';
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream out=new ObjectInputStream(new FileInputStream ("D:/ca/person.txt"));
        Person p= (Person) out.readObject();
        System.out.println(p.toString());
    }
}

Person{age=22, sex=男, name=’小红’}

序列化版本号serialVersionUID

java序列化提供了一个private static final long serialVersionUID 的序列化版本号,版本号相同,即使更改了序列化属性,对象也能正确被反序列化回来。

反序列化使用的class版本号与序列化使用的不一致,会报InvalidClassException异常。

序列化版本号可自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,这样随着class的升级,就无法正确反序列化,不利于jvm间的移植,可能class文件没有更改,但不同jvm可能计算的规则不一样,这样也会导致无法反序列化。

使用场景

  • 需要网络传输的对象都需要实现序列化接口
  • 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化
  • 某个变量不被序列化,使用transient修饰
  • 序列化对象的引用类型成员变量,也必须是可序列化的
  • 反序列化时必须有序列化对象的class文件
  • 通过文件、网络读取序列化后的对象时,必须按照实际写入的顺序读取
  • 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则
  • 同一对象序列化多次,第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化
  • 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级

4.流体系图

image.png

5.BIO、NIO、AIO

BIO:Block IO 同步阻塞式 IO,数据的读取写入必须阻塞在一个线程内等待其完成。模式简单使用方便,并发处理能力低。

NIO: 同步非阻塞 IO,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发

AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2。在 Java 7 中引入,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制,即应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。