地址: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---