nio--01

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章