Java-IO与NIO

Java-IO/NIO 原文地址


Java 的 I/O 可以分成以下几类:

  • 磁盘操作:File
  • 字节操作:InputStream 和 OutputStream
  • 字符操作:Reader 和 Writer
  • 对象操作:Serializable
  • 网络操作:Socket
  • 新的输入/输出:NIO

IO 流的分类:

  • 可以分为输入/输出流。
  • 按照操作可以分为字节流和字符流
  • 按照流的角色可以分为节点流和处理流
  • InputStream/Reader 所有输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutPutStream/Writer 所有输出流的基类,前者是字节输出流,厚泽是字符输出流。

主要内容

一、NIO 的特性/NIO 与 IO 的区别

  • IO 是面向流的,NIO 是面向缓冲区的。
  • IO 流是阻塞的,NIO 流是不阻塞的。
  • NIO 有选择器,而 IO 没有。

二、读数据和写数据的方式

  • 从通道进行数据读取:创建一个缓冲区,然后请求通道读取数据。
  • 从通道进行数据写入:创建一个缓冲区,填充数据,并要求通道写入数据。

三、NIO 核心组件

  • Buffer
  • Channels
  • Selectors

Buffer(缓冲区)

1 . 介绍

  • Java NIO Buffers 用于和 NIO Channel 交互。从 Channel 中读取数据到 buffers 里,
    从 Buffer 把数据写入到 Channels。
  • Buffer 本质是一块内存区域。
  • 三个属性必须掌握的,分别为:capacity 容量,position 位置,limit 限制。

2 . 常见方法

  • Buffer chear()
  • Buffer flip()
  • Buffer rewind()
  • Buffer position(int newPosition)

Channel(通道)

1 . 介绍

  • NIO 中的所有 IO 都是从 Channel 开始的。
  • NIO Channel 通道和流的区别。
    2 . FileChannel 的使用(略)。
    3 . SocketChannel 和 ServerSocketChannel 的使用(略)。
    4 . DatagramChannel 的 使用(略)。
    5 . Scatter / Gather
  • Scatter:从一个 Channel 读取的信息分散到 N 个缓冲区中(Buffer)。
  • Gather:将 N 个 Buffer 里面内容按照顺序发送到一个 Channel。
    6 . 通道之间的数据传输
  • NIO 中如果一个 channel 是 FileChannel 类型的,那么他可以直接把数据传输到另一个 Channel。
  • transferFrom() : transferFrom 方法把数据从通道源传输到 FileChannel
  • transferTo() : transferTo 方法把 FileChannel 数据传输到另一个 channel。

Selector(选择器)

1 . 介绍

  • NIO 实现了 IO 多路复用中的 Reactor 模型,一个县城使用 一个 Selector 通过轮询的方式去监听多个通道(channel)上的时间,从而让一个县城就可以处理多个事件。
  • 通过配置监听的通道 Channel 为非阻塞,那么当 Channel 上的 IO 事件还未到达时,就不会进入阻塞状态一直等待,而是继续轮训其他 Channel,找到状态是否处于可读、可写。
  • 使用 Selector 的好处在于:使用更少的县城来就可以处理通道了,相比使用多个线程,避免了上线文切换带来的开销。
  • 应该注意的是,只有套接字 Channel 才能配置为 非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞没有意义。

2 . 使用方法

  • 创建选择器

    Selector selector=Selector.open();
  • 注册 Channel 到 Selector(Channel 必须是非阻塞的)

    ServerSocketChannel ssChannel=ServerSocketChannel.open();
    ssChannel.configureBlocking(false);
    ssChannel.register(selector,SelectionKey.OP_ACCEPT);

总结

面向 Stream 和面向 Buffer

  • Java NIO 和 IO 之间最大的区别是 IO 是面向流(Stream),NIO 是面向块(Buffer),所以,这意味着什么?
  面向流意味着从流中一次可以读取一个或多个字节,拿到读取的这些做什么你说了算,这里没有任何缓存(这里指的是使用流没有任何缓存,接收或者发送的数据是缓存到操作系统中的,流就像一根水管从操作系统的缓存中读取数据)而且只能顺序从流中读取数据,如果需要跳过一些字节或者再读取已经读过的字节,你必须将从流中读取的数据先缓存起来。

  面向块的处理方式有些不同,数据是先被 读/写到 buffer 中的,根据需要你可以控制读取什么位置的数据。这在处理的过程中给用户多了一些灵活性,然而,你需要额外做的工作是检查你需要的数据是否已经全部到了 buffer 中,你还需要保证当有更多的数据进入 buffer 中时,buffer 中未处理的数据不会被覆盖

阻塞 IO 和非阻塞 IO

所有的Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞知道读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情

java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据

NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行

使用场景

  • NIO 允许你用一个单独的线程或几个线程管理很多个 channels(网络的或者文件的),代价是程序的处理和处理 IO 相比更加复杂
  • 如果你需要同时管理成千上万的连接,但是每个连接只发送少量数据,例如一个聊天服务器,用 NIO 实现会更好一些,相似的,如果你需要保持很多个到其他电脑的连接,例如 P2P 网络,用一个单独的线程来管理所有出口连接是比较合适的
  • 如果你只有少量的连接但是每个连接都占有很高的带宽,同时发送很多数据,传统的 IO 会更适合

我在这里等你

猜你喜欢

转载自www.cnblogs.com/zyhbook/p/12154428.html