Nmap recursion air Validator electron教程 纯html网页模板 java两个数组合并 oracle时间格式化 matlab求向量的模 centos定时任务 python3教程 python中的index python的def python变量定义 python文件读取 java查找字符串 randomjava java获取当前年月 java数组追加 java字符串比较 java定义变量 java如何编写接口 linux中sudo java网络编程实例 sp5 按钮制作 一键换系统 mathcad15 联想小新键盘灯怎么开 绿幕抠图 压枪软件 抠图软件免费版 winfax 加速软件 燃烧之血十字架 失心迷宫怎么打 起义任务线 内存条是什么 红巨星插件 layout软件
当前位置: 首页 > 学习教程  > 编程语言

JAVA 基础 day16 NIO

2020/8/11 20:18:21 文章标签:

NIO

Java Non-blocking IO或Java New IO,是从JDK1.4 开始引入 的一套新的IO,为所有的原始类型(boolean类型除外)提供缓存支持的 数据容器
使用它可以提供非阻塞式的高伸缩性网络
jdk 1.7后加入AIO(NIO2)
在这里插入图片描述
在这里插入图片描述

Buffer缓冲区

在这里插入图片描述
子类中没有boolean

Buffer基本使用

在这里插入图片描述
allocate()堆中开辟 alloacteDirect()物理内存开辟
在这里插入图片描述

在这里插入图片描述

public class TestBuffer {
    public static void main(String[] args) {
        // 1.创建缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);// 实际上就是分配一个数组
        // 2.put方法存放珊瑚橘
        byte[] bytes = "chichi yyds".getBytes();
        buffer.put(bytes);
        // 3.翻转缓冲区(把写入模式转为读读取模式)
        buffer.flip();
        // 4.读取
        byte[] bytes1 = new byte[buffer.limit()];
        buffer.get(bytes1);
        System.out.println(new String(bytes1,0,bytes.length));
        // 5.清空
        buffer.clear();
    }
}

Buffer原理

在这里插入图片描述
mark<=position<=limit<=capcity 标记 位置, 限制, 容量

Buffer过程

创建后默认为写模式,position初始数组0下标(初始位置),limit与capcity都在末尾,每次写入position后移,flip()后,limit指向此时position的位置,position回到起始位置。

清空clear后,三个指针回到缓冲区创建的初始位置(clear并没有删除数据,数据处于遗忘状态,再次存入数据是会覆盖原数据),但是已经读不到数据了(limit限制,只能到达新元素的位置),
使用compact方法可以保存未读数据(此时position~limit)到Buffer起始处,flip()翻转后可以再次读到数据了

mark标记可以理解为一个书签,调用mark()方法可以在此时position打上一个标签,当position后移后,调用reset方法可以把position置为mark位置

Channel通道

在这里插入图片描述
创建方式有两种:
1.使用字节流或RandomAccessFile来获取一个FileChannel实例。
2.JDK1.7之后才能使用, FileChannel.open()方法
3.使用工具类Channels的newChannel()方法
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
直接缓冲区不能使用.array()方法返回数组

channel通道写

public static void write() throws Exception{
        // 1.创建通道
        // 1.1 使用字节文件流
//        RandomAccessFile file = new RandomAccessFile("chichi.text", "rw");
//        FileChannel channel = file.getChannel();
        //使用工具类或的通道
//        FileChannel Channel = (FileChannel)Channels.newChannel(new FileOutputStream("chichi.txt"))
        // 1.2open方法 打开方式若为create_new,文件错在会报错
        FileChannel open = FileChannel.open(Paths.get("chichi.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

        ByteBuffer allocate = ByteBuffer.allocate(1024);
        allocate.put("赤赤 永远的神".getBytes());
        //转换模式 写入通道
        allocate.flip();
        open.write(allocate);
        // 关闭 channel关闭会自动关闭缓冲区
        open.close();

    }

channel关闭会自动关闭缓冲区

channel通道读

public static void read() throws Exception{
        //工具类创建通道
//        FileChannel Channel = (FileChannel)Channels.newChannel(new FileInputStream("chichi.txt"));
        FileChannel open = FileChannel.open(Paths.get("chichi.txt"), StandardOpenOption.READ);
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 创建解码器 当接收缓冲区空间小,读取汉字时可能会因读不全(三个字节)而产生乱码
        // 英文时无此问题,直接用ByteBuffer读就可以
        // 通过解码器,把ByteBuffer解码成 CharBuffer
        CharsetDecoder charsetDecoder = Charset.forName("utf-8").newDecoder();

        CharBuffer charBuffer = CharBuffer.allocate(10);//大小要有
        //read时把通道中的读到Buffer中,时写模式
        while (open.read(byteBuffer)>0){//读到末尾会返回0,-1,
            byteBuffer.flip();//变写为读
            charsetDecoder.decode(byteBuffer, charBuffer, false);//false默认
            charBuffer.flip();//变写为读
            System.out.println(charBuffer.toString());
            byteBuffer.compact();//可能有没读完的字节,不能clear
            charBuffer.clear();
        }
        open.close();
    }

普通IO操作
在这里插入图片描述

文件大的时候使用直接内存,文件小的时候用间接内存

直接缓冲区的使用,可以提高读写的速度。但是直接缓冲区的创建和销毁的 开销比较大,一般大文件操作或能显著提高读写性能时使用

内存映射

• 内存映射文件也属于直接缓冲区

注意:如果文件超过2G,需要分多个文件映射

		FileChannel readChannel = FileChannel.open(Paths.get("kekeluo.jpg"), StandardOpenOption.READ);
        FileChannel writeChannel = FileChannel.open(Paths.get("chichi.jpg"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        // 直接内存映射文件 文件超过2G,采用多映射
        MappedByteBuffer map=readChannel.map(FileChannel.MapMode.READ_ONLY,0,1);
        MappedByteBuffer map2=readChannel.map(FileChannel.MapMode.READ_ONLY,1, readChannel.size()-1);
        // 内存映射文件写入
        writeChannel.write(map);
        writeChannel.write(map2);
        // 关闭
        writeChannel.close();
        readChannel.close();
        System.out.println("复制完毕");

NIO网络编程(TCP)

应对任务小,高并发
既支持阻塞式又支持非阻塞式
在这里插入图片描述
NIO阻塞式编程

public class Server {
    public static void main(String[] args) throws Exception{
        ServerSocketChannel listener=ServerSocketChannel.open();
        // 绑定地址和端口号
        listener.bind(new InetSocketAddress("10.0.139.195",8888));
        // 监听
        SocketChannel socketChannel = listener.accept();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        socketChannel.read(byteBuffer);
        byteBuffer.flip();
        System.out.println(socketChannel.getRemoteAddress()+new String(byteBuffer.array(),0,byteBuffer.limit()));//array返回数组
        byteBuffer.clear();
        //关闭
        socketChannel.close();
        listener.close();


    }
}

 public static void main(String[] args) throws Exception{
        // 客户端可以直接地址(客户端的)
        SocketChannel socketChannel=SocketChannel.open(new InetSocketAddress("10.0.139.195",8888));
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        buffer.put("chichi yyds".getBytes());
        buffer.flip();
        socketChannel.write(buffer);
        buffer.clear();
        socketChannel.close();
    }

Selector

多路复用
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

NIO非阻塞式网络编程

public class Server {
    public static void main(String[] args) throws Exception{
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
        // 绑定地址和端口
        serverSocketChannel.bind(new InetSocketAddress("10.0.139.195", 8888));
        // 设置为非阻塞式
        serverSocketChannel.configureBlocking(false);
        // 创建选择器
        Selector selector=Selector.open();
        // 注册到选择器
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 轮询 select() 阻塞方法,没有时间发送阻塞(选择器中没有位置)
        // 返回已更新其准备就绪操作集的键的数目,该数目可能为零
        System.out.println("客户端启动了");
        while (selector.select()>0){
            //返回可用的键集
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                if(selectionKey.isAcceptable()){
                    //表示有客户端请求
                    SocketChannel socketChannel = serverSocketChannel.accept();//不会阻塞,可能有其他的在运行
                    System.out.println(socketChannel.getRemoteAddress()+"进入聊天室");
                    //设置非阻塞
                    socketChannel.configureBlocking(false);
                    //注册到selector
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }else if(selectionKey.isReadable()){
                    //获取到此键所对应的通道
                    SocketChannel channel = (SocketChannel)selectionKey.channel();
                    ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
                    int len=0;
                    //客户端发送空,len为0
                    //如果某个通道处于阻塞模式,并且缓冲区中至少剩余一个字节,则在读取至少一个字节之前将阻塞此方法
                    try {
                        while ((len=channel.read(byteBuffer))>0){//不会阻塞
                            byteBuffer.flip();
                            System.out.println(channel.getRemoteAddress()+":::"+new String(byteBuffer.array(),0,byteBuffer.limit()));
                            byteBuffer.clear();

                        }
                        if (len==-1){
                            System.out.println(channel.getRemoteAddress()+"退出了聊天室");
                            channel.close();
                        }
                    } catch (IOException e) {
                        System.out.println(channel.getRemoteAddress()+"异常退出了");
                        channel.close();
                    }
                }
                //处理过的键删除
                iterator.remove();
            }
        }
    serverSocketChannel.close();
    }
}



public class Client {
    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner(System.in);
        SocketChannel socketChannel=SocketChannel.open(new InetSocketAddress("10.0.139.195", 8888));
        socketChannel.configureBlocking(false);
        while (true){
            String data=scanner.nextLine();
            if("886".equals(data)){
                break;
            }
            ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
            byteBuffer.put(data.getBytes());
            byteBuffer.flip();
            socketChannel.write(byteBuffer);
            byteBuffer.clear();
        }
        socketChannel.close();
    }
}

本文链接: http://www.dtmao.cc/news_show_100314.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?