IO流

IO 流

类型

为什么要区分字节流和字符流

  • java虚拟机转换字符需要消化性能,视频和图片等不需要字符,直接传字节就行

1. 字节流

1. InputStream/OutputStream
2. dataInputStream /OutputStream
    - 读各种类型 
3. ObjectInputStream/OutputStream
    - 序列化和反序列化
    - 不想要序列化的属性加上 `trasient`

2. 字符流

1. Reader/Writer

3. 特殊的流

1. RandomAccessFile
    - 随机访问流,可以随机访问文件,可以用于分片上传
2. PrintWriter
    - 字节打印流,sout就是使用的他
    

NIO

Buffer

重要属性:

  1. capacity
  2. limit
  3. positoin
  4. mark

两种状态

  1. 写模式(默认)
  2. 读模式
  3. 当这两种模式切换的时候上面的参数也会跟着变化
  4. 注意有坑,当你写入数据完成的时候,你要切换成读模式,以便让底层可以读buffer

Channel

  1. 全双工
  2. FileChannel(文件)、
  3. SocketChannel、ServerSocketChannel(TCP链接)、
  4. DataGramChannel(UDP链接)

Selector

  1. 工作原理

    • channel通过注册事件给Selector然后给一个SelectionKey,当事件完成的时候,转换为就绪状态,然后selector轮询出来,然后将这个ChannelSelectionKey放到就绪集合中,线程通过这个key去找到对应的channel读取数据/写入数据
  2. Selector 可以监听以下四种事件类型:

    1. SelectionKey.OP_ACCEPT:表示通道接受连接的事件,这通常用于 ServerSocketChannel。
    2. SelectionKey.OP_CONNECT:表示通道完成连接的事件,这通常用于 SocketChannel。
    3. SelectionKey.OP_READ:表示通道准备好进行读取的事件,即有数据可读。
    4. SelectionKey.OP_WRITE:表示通道准备好进行写入的事件,即可以写入数据。
  3. SelectionKey集合

    1. 所有Key集合: keys()获得
    2. 被选择的key集合: .selected()获得
    3. 取消的key集合: 不能获得

NIO使用方法

RandomAccessFile reader = new RandomAccessFile("/Users/guide/Documents/test_read.in", "r");
FileChannel channel = reader.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);

把任意IO流变成NIO

// 将任意 InputStream 包装成 ReadableByteChannel
ReadableByteChannel myChannel = Channels.newChannel(System.in);

如何遍历SelectionKey集合进行处理

Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if (key != null) {
        if (key.isAcceptable()) {
            // ServerSocketChannel 接收了一个新连接
        } else if (key.isConnectable()) {
            // 表示一个新连接建立
        } else if (key.isReadable()) {
            // Channel 有准备好的数据,可以读取
        } else if (key.isWritable()) {
            // Channel 有空闲的 Buffer,可以写入数据
        }
    }
    keyIterator.remove();
}

问题

// 字节流转换为字符流的桥梁
public class InputStreamReader extends Reader {
}

// 用于读取字符文件
public class FileReader extends InputStreamReader {
}

为什么缓冲流会减少io消耗

  1. 减少用户态和内核态的切换和cpu的上下文切换,
    • 上下文切换会先保存数据,然后再加载数据,浪费时间
  2. 减少磁盘写入
    • 磁盘写入和读取一次会读取一页或者一个扇区
    • 一个写入多个就写到一页里面,可以减少磁盘操作