您的位置 首页 > 腾讯云社区

Java知识点——NIO和BIO---用户7073689

NIO和BIO1. NIO和BIO1.1 BIO概述BIO BIO ==> Basic IO (基本IO), Block IO(阻塞IO) Scanner操作,文件读写操作,Socket数据传输操作... 都是BIO 比如TCP群聊,私聊聊天室 Socket涉及到的IO,也是BIO 资源浪费: 1. 多线程,每一个Socket会对应一个线程,如果用户量巨大,会导致线程过 多,资源处理过多 2. 采用阻塞状态,一旦进入阻塞,代码无法执行其他操作。 3. 承载量一般,吞吐量比较小,同时可靠性不佳1.2 NIO概述NIO NIO ==> New IO(新IO), Non-Block IO(非阻塞IO) NIO非阻塞IO,允许当前程序在处理IO事务时,不会影响其他程序的运行,可以在不使用多线程的情况下,满足IO操作要求。 三大核心部分: 通道 Channel 文件操作,网络数据传递操作使用的通道 缓冲 Buffer 缓冲使用可以提高操作效率,减少不必要的读写次数 选择器 Selector 真·核心 老大 boss

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvUiQgVM-1584882587306)(img/NIO图例.png)]

1.3 Buffer Channel完成文件操作1.3.1 常用APIjava.nio.Buffer Buffer缓冲区 ByteBuffer 字节缓冲 常用 ShortBuffer IntBuffer LongBuffer CharBuffer 字符缓冲 常用 FloatBuffer DoubleBuffer 常用方法: public static ByteBuffer allocate(int capacity); 按照指定的字节数分配对应的缓冲区空间,保存字节数据 public byte get(); 从字节缓冲区对象中读取一个byte类型数组 public final Buffer flip(); 翻转缓冲区,回到缓冲区的开始位置。 public static ByteBuffer wrap(byte[] arr); 存入一个byte类型数组到缓冲区,会得到一个新的ByteBuffer public static ByteBuffer put(byte[] b); 将字节数组存入缓冲区 Channel接口,通道接口 FileChannel 文件操作通道 DatagramChannel UDP协议数据包操作的Channel ServerSocketChannel TCP服务端ServerSocket对应Channel SocketChannel TCP客户端Socket对应Channel 首先操作文件,以FileChannel为例 public long read(ByteBuffer buffer); 从通道中读取数据到ByteBuffer中 public long write(ByteBuffer buffer); 从Buffer中写数据到通道中 public long transferFrom(ReadableByteChannel src, long position, long count) 从指定srcChannel中,指定位置position开始,读取count个元素,到当前通道中 文件复制操作。 public long transferTo(long position, long count, WritableByteChannel target) 将当前通道中的数据写入到target中,从当前通道的position位置开始,计数count1.3.2 操作文件数据package com.qfedu.b_niofile; import org.junit.Test; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * @author Anonymous 2020/3/13 15:17 */ public class FileNioTest { /* 通过NIO写入数据到文件中的操作 */ @Test public void testNioFileWrite() throws IOException { // 1. 文件操作字节输出流 FileOutputStream fos = new FileOutputStream("D:/aaa/1.txt"); // 2. 利用文件操作输出字节流对象获取对应的Channel通道 FileChannel foc = fos.getChannel(); // 3. 准备一个缓冲区 4KB缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024 * 4); // 4. 准备数据,放入缓冲区 String str = "测试NIO"; buffer.put(str.getBytes()); // 5. 存在缓冲区数据放入之后,缓冲区指针发生改变,到达存入数据的末尾 // 如果此时调用写入操作,会从存入缓冲区之后开始保存 // 让缓冲区指针回到最初的起点,并且操作写入程序,只会保存缓冲区内的有效数据 buffer.flip(); // 6. 缓冲区数据写入到通道中 foc.write(buffer); // 7. 关闭资源 fos.close(); } @Test public void testNioFileRead() throws IOException { // 1. 文件字节操作输入流 FileInputStream fis = new FileInputStream("D:/aaa/1.txt"); // 2. FileChannel FileChannel fic = fis.getChannel(); // 3. 准备缓冲 ByteBuffer buffer = ByteBuffer.allocate(1024); // 4. 从Channel读取数据保存到缓冲区中 int read = fic.read(buffer); System.out.println(read); // 5. 展示数据 // String(byte[] arr, int off, int count) System.out.println(new String(buffer.array(), 0, read)); // 6. 关闭资源 fis.close(); } // 130 @Test public void testCopyFile() throws IOException { long start = System.currentTimeMillis(); // 1. 安排输出流和输入流 FileInputStream fis = new FileInputStream("D:/aaa/1.mp4"); FileOutputStream fos = new FileOutputStream("D:/aaa/2.mp4"); // 2. 准备两个Channel FileChannel srcChannel = fis.getChannel(); FileChannel dstChannel = fos.getChannel(); // 3. 拷贝方法 srcChannel.transferTo(0, srcChannel.size(), dstChannel); // dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); // 4. 关闭资源 fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println("Time:" + (end - start)); } // 300 @Test public void testCopyUseBuffer() throws IOException { long start = System.currentTimeMillis(); BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/aaa/1.mp4")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/aaa/3.mp4")); int length = -1; byte[] buf = new byte[4 * 1024]; while ((length = bis.read(buf)) != -1) { bos.write(buf, 0, length); } bos.close(); bis.close(); long end = System.currentTimeMillis(); System.out.println("Time:" + (end - start)); } }1.4 网络编程使用NIO【重点】1.4.1 Selector选择器老大Selector 选择器,网络编程使用NIO的大哥!!! 服务器可以执行一个线程,运行Selector程序,进行监听操作。 新连接, 已经连接, 读取数据,写入数据 Selector常用方法: public static Selector Open(); 得到一个选择器对象 public int select(long timeout); 监听所有注册通道,存在IO流操作是,会将对应的信息SelectionKey存入到内部的集 合中,参数是一个超时时间 public Set<SelectionKey> selectionKeys(); 返回当前Selector内部集合中保存的所有SelectionKey

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sqrm92Ed-1584882587307)(img/Selector大哥.png)]

1.4.2 SelectionKeySelectionKey 表示Selector和网络通道之间的关系 int OP_ACCEPT; 16 需要连接 int OP_CONNECT; 8 已经连接 int OP_READ; 1 读取操作 int OP_WRITE; 4 写入操作 SelectionKey public abstract Selector selector(); 得到与之关联的 Selector 对象 public abstract SelectableChannel channel(); 得到与之关联的通道 public final Object attachment(); 得到与之关联的共享数据 public abstract SelectionKey interestOps(int ops); 设置或改变监听事件 public final boolean isAcceptable(); 是否可以 accept public final boolean isReadable(); 是否可以读 public final boolean isWritable(); 是否可以写1.4.3 ServerSocketChannelServerSocketChannel 服务端Socket程序对应的Channel通道 常用方法: public static ServerSocketChannel open(); 开启服务器ServerSocketChannel通道,等于开始服务器程序 public final ServerSocketChannel bind(SocketAddress local); 设置服务器端端口号 public final SelectableChannel configureBlocking(boolean block); 设置阻塞或非阻塞模式, 取值 false 表示采用非阻塞模式 public SocketChannel accept(); [非阻塞] 获取一个客户端连接,并且得到对应的操作通道 public final SelectionKey register(Selector sel, int ops); [重点方法] 注册当前选择器,并且选择监听什么事件1.4.4 SocketChannelSocketChannel 客户端Socket对应的Channel对象 常用方法: public static SocketChannel open(); 打卡一个Socket客户端Channel对象 public final SelectableChannel configureBlocking(boolean block) 这里可以设置是阻塞状态,还是非阻塞状态 false,表示非阻塞 public boolean connect(SocketAddress remote); 连接服务器 public boolean finishConnect(); 如果connect连接失败,可以通过finishConnect继续连接 public int write(ByteBuffer buf); 写入数据到缓冲流中 public int read(ByteBuffer buf); 、 从缓冲流中读取数据 public final SelectionKey register(Selector sel, int ops, Object attechment); 注册当前SocketChannel,选择对应的监听操作,并且可以带有Object attachment参数 public final void close(); 关闭SocketChannel ---来自腾讯云社区的---用户7073689

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: