3. NIO
3.1简介
NIO是JDK1.4的时候出现了一个新的IO,用来代替传统的IO流。
NIO是基于通道(Channel),面向缓冲区(Buffer)的。
在JDK1.7的时候,为NIO添加了一些新的特定。被称为NIO.2
3.2 NIO组成
Channels:通道 Buffer:缓冲区 Selectors:选择器
Channels和Buffer是新IO中的两个核⼼对象,Channel是对传统的输⼊/输出系统的模拟,在新IO系统中所有的数据都需要通过通道传输。
Channels与传统的 InputStream , OutputStrem 最⼤的区别在于它提供了⼀个map()⽅法,通过该map()⽅法可以直接将"⼀块数据"映射到 内存中,如果说传统的输⼊/输出系统是⾯向流处理,则新IO则是⾯向块的处理 。
Buffer可以被理解为⼀个容器(缓冲区,数组),发送到Channel中的所有对象都必须⾸先 放到Buffer中,⽽从Channel中读取的数据也必须 放到Buffer中,也就是说数据可以从Channel读取到Buffer中,也可以从Buffer写到 Channel中。
3.3 和传统的IO区别
1.IO⾯向流,NIO⾯向缓冲区 Java IO⾯向流意味着每次从流中读⼀个或多个字节,直⾄读取所有字节,它们没有被 缓存在任何地⽅。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数 据,需要先将它缓存到⼀个缓冲区。 Java NIO的缓冲导向⽅法略有不同。数据读取到 ⼀个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活 性. 2.IO是阻塞式的,NIO有⾮阻塞式的 Java IO的各种流是阻塞的。这意味着,当⼀个线程调⽤read() 或 write()时,该 线程被阻塞,直到有⼀些数据被读取,或数据完全写⼊。该线程在此期间不能再⼲任何事 情了。Java NIO的⾮阻塞模式,使⼀个线程从某通道发送请求读取数据,但是它仅能得 到⽬前可⽤的数据,如果⽬前没有数据可⽤时,就什么都不会获取,⽽不是保持线程阻塞 所以直⾄数据变的可以读取之前,该线程可以继续做其他的事情。 ⾮阻塞写也是如此。 3.IO没有选择器,NIO有选择器 Java NIO的选择器允许⼀个单独的线程来监视多个输⼊通道,你可以注册多个通道使⽤ ⼀个选择器,然后使⽤⼀个单独的线程来“选择”通道:这些通道⾥已经有可以处理的输 ⼊,或者选择已准备写⼊的通道。这种选择机制,使得⼀个单独的线程很容易来管理多个 通道.
4. Buffer缓冲区
4.1缓冲区的概念
其实是⼀个⽤来存储基本数据类型的⼀个容器, 类似于⼀个数组。
缓冲区, 可以按照存储的数据类型不同, 将缓冲区分为:
ByteBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、 DoubleBuffer、CharBuffer
但是, 要注意, 并没有BooleanBuffer!
这些缓冲区, 虽然是不同的类, 但是他们拥有的相同的属性和⽅法。 因为他们都继 承⾃相同的⽗类 Buffer。
4.2 Buffer的几个属性
-
capacity: 容量。 代表⼀个缓冲区的最⼤的容量, 缓冲区⼀旦开辟完成, 将⽆法修改。
-
limit: 限制。 表示缓冲区中有多少数据可以操作。
-
position: 位置。 表示当前要操作缓冲区中的哪⼀个下标的数据。
-
mark: 标记。 在缓冲区中设计⼀个标记, 配合 reset() ⽅法使⽤, 修改position 的值
4.3 Buffer常用的方法
方法 | 描述 |
---|---|
allocate(int capacity) | 开辟⼀个缓冲区, 并设置缓冲区的容量 |
put(byte b) | 将⼀个字节的数据存⼊缓冲区, position向后挪动⼀位。 |
put(byte[] arr) | 将⼀个字节数组的数据存⼊缓冲区, position向后挪动数组⻓度位 |
flip() | 将缓冲区切换成读模式。 |
get() | 获取⼀个字节的数据。 |
get(byte[] arr) | 将缓冲区中的数据读取到数组中。 |
mark() | 在缓冲区中添加⼀个标记, 将mark属性的值设置为当前的position的值。 |
reset() | 将属性position的值, 修改为mark记录的值。 |
rewind() | 倒回, 将position的值重置为0, 同时清空mark的标记的值。 |
clear() | 重置所有的属性为缓冲区刚刚被开辟时的状态 |
4.4 注意事项
-
在向缓冲区中写数据的时候, 要注意:不要超出缓冲区的范围。如果超出范围 了,会出现BufferOverflowException 异常, 且本次put的所有数据都不会存⼊到缓冲区中
缓冲区, 其实有两种模式: 分别是读模式和写模式。 读模式: 就是从缓冲区中读取数据。 写模式: 就是将数据写⼊到缓冲区。 ⼀个刚刚被开辟的缓冲区, 默认处于写模式
4.5 缓冲区的详解
其实, 缓冲区中, 并没有所谓的读模式和写模式。 其实所谓“读模式”和“写模式”, 只是逻辑上的区分。
⼀个处于“读模式”下的缓冲区, 依然可以写数据。
⼀个处理“写模式”下的缓冲区, 依然可以读取数据。
上述⽅法中, 基本所有的⽅法, 都是围绕着缓冲区中的⼏个属性进⾏的
5. Channel通道
5.1 通道的简介
通道Channel,就是⽂件和程序之间的连接。在NIO中,数据的传递,是由缓冲区实现的,通道本身并不负责数据的传递。
通道在 java.nio.channels 包中,常⻅的Channel⼦类:
-
本地⽂件: FileChannel
-
⽹络⽂件: SocketChannel, ServerSocketChannel, DatagramChannel
Channel类似于传统的流对象,但与传统的流对象有两个主要的区别:
-
Channel可以直接将我指定⽂件的部分或全部直接映射成Buffer
-
程序不能直接访问Channel中的数据,包括读取,写⼊都不⾏.Channel只能与 Buffer进⾏交互
5.2 通道的打开方式
-
可以使⽤⽀持通道的类, getChannel()⽅法获取通道。
-
本地⽂件: FileInputStream、FileOutputStream
-
⽹络⽂件: Socket、ServerSocket、DatagramSocket
-
-
在NIO.2中,使⽤FileChannel.open()⽅法打开通道。
-
在NIO.2中,使⽤Files⼯具类newXXX()⽅法打开通道。
5.3 使用 FileChannel 读写数据
在使⽤FileChannel之前,必须先打开它。但是,我们⽆法直接打开⼀个 FileChannel,需要通过使⽤⼀个InputStream、OutputStream的getChannel()⽅法 来返回对应的Channe
6. JVM
6.1 类加载器 ClassLoader
类加载器, 负责加载class⽂件。 class⽂件在⽂件开头有特定的⽂件标示。
ClassLoader只负责class⽂件的加载, ⾄于它是否可以运⾏, 则由Execution Engine决定。
7.Properties
7.1简介
-
概述
Properties也不是⼀个IO流, 是⼀个集合。 是Hashtable的⼦类。
使⽤Properties主要是为了描述程序中的属性列表⽂件。 有时候, 我们会将⼀些⽐ 较简单的项⽬的配置信息, 以 .properties 格式的⽂件进⾏存储。 可以使⽤ Properties对象读写 .properties ⽂件。
-
注意
因为存储的是属性,属性本来就是以键值对的⽅式存储.这⾥的键和值都必须是字符串. 所以不需要考虑泛型
-
为什么要在这⾥讲Properties?
因为他的使⽤与流紧密相关
-
Properties作⽤
1.是HashTable的⼦类,所以也是键值对形式,保存,操作更容易
2.默认键值都是字符串,所以不需要再考虑泛型
3.提供了⼀批好⽤的⽅法,⽅便使⽤(load(),store(),list()等)