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---

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