什么是流

java中将数据的处理,输入/输出抽象为流的概念,及从一端到另一端。所以流是具有方向性的,流的来源包括文件、网络、应用程序的输出等

流的分类

1. 根据流处理的数据类型分为:字节流、字符流

2. 根据流的方向性分为:输入流、输出流

3. 根据流的功能分为:节点流、处理流

1和2比较好理解,3中节点流代表的是纯原生的字节处理方案,处理流指的是对原生的字节流进行了包装处理,如BufferedInputStream等。

Java中流的整体关系结构

java提供了非常多的流处理类,下面是流之间的继承层次关系

InputStream类相关的层次关系

java 地层流 java io流的层次结构_java

OutputStream类相关的层次关系

java 地层流 java io流的层次结构_io_02

流的处理都是对字节进行处理,但问什么会出现字符流的概念,因为,大部分情况下,我们操作的流都是对于文本,所以字符的存在是为了简化操作而诞生的。

而字节向字符转化又存在编码问题,所以编码的处理时必不可少的,编码问题参考文章传送门

Reader类相关的层次关系

java 地层流 java io流的层次结构_socket_03

Writer类相关的层次关系

java 地层流 java io流的层次结构_数据_04

IO流中存在的设计模式

1. 装饰者模式

各种流之间分别采用的是FilterInputStream、FilterOutputStream作为装饰者,分别对InputStream、OutputStream进行装饰,多个装饰者可以直接继承FilterInputStream和FilterOutputStream。

对于装饰者模式理解的最简单例子就是汽车装饰的例子:

package top.wzblog.test;

public class test {
    public static void main(String args[]){
        test t = new test();
        //这里为内部类的实例创建
        test.BMCar bmCar = t.new BMCar(t.new QQCar());
        bmCar.run();
    }

    interface Car{
        void run();
    }
    
    class QQCar implements Car{
        @Override
        public void run() {
            System.out.println("QQCAR 60 km/h");
        }
    }
    
    class BMCar implements Car{
        
        private Car car;
        
        public BMCar(Car car){
            this.car = car;
        }
        
        @Override
        public void run() {
            car.run();
            System.out.println("BMCAR 120 km/h");
        }
    }
}

2. 适配器模式

从字节流到字符流肯定需要一个中间者进行接口的适配才能进行转换,这个类就是InputStreamReader、OutputStreamWriter

转换图为:

java 地层流 java io流的层次结构_java_05

java 地层流 java io流的层次结构_socket_06

StreamDecoder、StreamEncoder为编解码过程

Java中Socket编程

socket是一个抽象的功能,完成了计算机之间的通信问题,可以把 Socket 比作为两个城市之间的交通工具,有了它,就可以在城市之间来回穿梭了。交通工具有多种,每种交通工具也有相应的交通规则。Socket 也一样,也有多种。大部分情况下我们使用的都是基于 TCP/IP 的流套接字,它是一种稳定的通信协议。

当连接建立时客户端和服务器都会使用一个端口占用进行通信,通过tcp的三次握手,当 Socket 对象创建时,操作系统将会为 InputStream 和 OutputStream 分别分配一定大小的缓冲区,数据的写入和读取都是通过这个缓存区完成的。

数据的接收是阻塞等待的,当数据到来、连接断开或者超时时才会结束等待

发送数据时,数据包的大小会根据缓冲区大小、网络状况等情况发生变化,如果需要提前将数据进行发送,可调用os.flush()方法