地址:https://www.bilibili.com/video/BV1ht41127od?from=search&seid=11989657092464585041
代码:
传统的io是面向流的:
nio是面向缓冲区的。
---01---
代码:
package com.atguigu.nio;
import java.nio.ByteBuffer;
import org.junit.Test;
/*
* 一、缓冲区(Buffer):在 Java NIO 中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据
*
* 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过 allocate() 获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法:
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性:
* capacity : 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit : 界限,表示缓冲区中可以操作数据的大小。(limit 后数据不能进行读写)
* position : 位置,表示缓冲区中正在操作数据的位置。
*
* mark : 标记,表示记录当前 position 的位置。可以通过 reset() 恢复到 mark 的位置
*
* 0 <= mark <= position <= limit <= capacity
*
* 四、直接缓冲区与非直接缓冲区:
* 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
* 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
*/
public class TestBuffer {
@Test
public void test3(){
//分配直接缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
System.out.println(buf.isDirect());
}
@Test
public void test2(){
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0, 2);
System.out.println(new String(dst, 0, 2));
System.out.println(buf.position());
//mark() : 标记
buf.mark();
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));
System.out.println(buf.position());
//reset() : 恢复到 mark 的位置
buf.reset();
System.out.println(buf.position());
//判断缓冲区中是否还有剩余数据
if(buf.hasRemaining()){
//获取缓冲区中可以操作的数量
System.out.println(buf.remaining());
}
}
@Test
public void test1(){
String str = "abcde";
//1. 分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("-----------------allocate()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//2. 利用 put() 存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("-----------------put()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//3. 切换读取数据模式
buf.flip();
System.out.println("-----------------flip()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//4. 利用 get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
System.out.println("-----------------get()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//5. rewind() : 可重复读
buf.rewind();
System.out.println("-----------------rewind()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
buf.clear();
System.out.println("-----------------clear()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
System.out.println((char)buf.get());
}
}
缓冲区的种类:ByteBuffer(char short int long float double)
一位是1个bit。一个字节是一个byte。
8bit=byte。
Bytebuffer的核心属性:
资料:
缓冲区的读写要切换的flip。
---------------------------------------------------------------------------------------------------------------------------
代码:
可见缓冲区是双向的。
recind就是可以重复读数据
清空,缓冲区数据依然存在,只是被遗忘状态的,还是可以拿出来的。
----------
看下mark。
position是下一个要写的位置
limit是第一个不能读取或者写入数据的索引
---02---
直接缓冲区和非直接缓冲区。
应用程序和磁盘之间传输数据是没有办法直接进行传输的。
为什么在物理内存中就可以提高效率呢?
左面是os右面是JVM。
内存映射文件。
内存映射文件:https://mp.weixin.qq.com/s/S9tNqTlCutRNKtKQCm6LnQ
这篇文章的精髓
虚拟内存,内存映射文件,直接缓冲区就是直接内存,映射到磁盘的地址,在物理内存中直接开辟缓冲区,第一次读取的话会缺页,就把磁盘的东西搞到物理内存上,要是不够的话就释放掉一些其他的物理内存。
应用程序直接面对的是物理内存映射文件,物理内存映射文件直接面对的是物理磁盘。
耗费的资源是比较大的。写入之后不归我们管什么时候写到磁盘是操作系统控制的。
断开引用到物理内存的引用才会释放。
MappedeByteBuffer:https://blog.csdn.net/qq_41969879/article/details/81629469
直接IO。
sendFile:https://www.jianshu.com/p/028cf0008ca5
mmap:https://www.jianshu.com/p/755338d11865
---04---
通道:
大量请求的话DMA总线会冲突的。
通道和cpu一样是一个完全独立的处理器,对于DMA。
代码:
通道的分类:
FileChanne
SocketChannel
ServerSocketChannel
DatagramChannel
---05---
1.非直接缓冲区
2.直接缓冲区
深入浅出MappedByteBuffer:https://blog.csdn.net/qq_41969879/article/details/81629469
---
测试效率,读一个大文件。
直接内存不是拷贝完事就是程序完事了,什么时候写入磁盘我们控制不了的,垃圾回收我们彻底释放资源。
---
通道之间的数据传输。
---06---
public static void test4() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");
//1. 获取通道
FileChannel channel1 = raf1.getChannel();
//2. 分配指定大小的缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
//3. 分散读取
ByteBuffer[] bufs = {buf1, buf2};
channel1.read(bufs);
for (ByteBuffer byteBuffer : bufs) {
byteBuffer.flip();
}
System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
System.out.println("-----------------");
System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));
//4. 聚集写入
RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");
FileChannel channel2 = raf2.getChannel();
channel2.write(bufs);
}
---07---
字符集:
---
---08---
阻塞和非阻塞。
解决就是每一个客户端发来的请求都独立的分配一个线程。
但是线程数量是有限的。
---09---
FileChannel不能切换非阻塞模式的。
通道操作缓冲区用来代替流。
---10---
---11---
---12---
---13---