Java nio基本知识1:channel和buffer

阻塞IO

读写时候阻塞,每个请求是一个线程

非阻塞IO

基于Reactor工作模式,IO不会阻塞,注册特定IO事件,发生特定事件时候系统会通知。核心对象是Selector,
读、写、注册发生时候selector可以找到发生事件的Selector Channel,获取客户端数据。

非阻塞IO事件本身不阻塞,但是获取事件的select()方法是阻塞的,本质是发生io时候,而不是以前只要IO流打开就一直等待。

NIO

核心组件:Channels Buffers Selectors

filechannel

写入文件小例子

public class io1 {
    public static void main(String[] args) throws IOException {
        File f = new File("C:\\Users\\86158\\Desktop\\datax.txt");
        RandomAccessFile ra = new RandomAccessFile(f,"rw");
        FileChannel fc = ra.getChannel();

        //创建buffer
        ByteBuffer bf = ByteBuffer.allocate(1024);

        String input = "abcdefg";

        bf.clear();
        bf.put(input.getBytes());
        bf.flip();

        while (bf.hasRemaining()){
            fc.write(bf);
        }
        fc.close();
    }
}

FileChannel
position在某些特定位置进行读写
size返回文件大小
truncate 截取字节
force 强制写入
transferTo/transferFrom 通道间数据传输

通道间数据传输小例子

public class io2 {
    public static void main(String[] args) throws IOException {
        File f = new File("C:\\Users\\86158\\Desktop\\datax.txt");
        File f2 = new File("C:\\Users\\86158\\Desktop\\datax2.txt");
        RandomAccessFile ra1 = new RandomAccessFile(f,"rw");
        RandomAccessFile ra2 = new RandomAccessFile(f2,"rw");
        FileChannel fc1 = ra1.getChannel();
        FileChannel fc2 = ra1.getChannel();

        //fc1数据传入fc2
        fc1.transferTo(0,fc1.size(),fc2);

    }
}


socketChannel

serverSocketChannel可以监听新进来的TCP连接的通道

监听8888端口

public class io3 {
    public static void main(String[] args) throws IOException, InterruptedException {
        int port = 8888;
        ByteBuffer bf = ByteBuffer.wrap("hello".getBytes());

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(port));

        //设置非阻塞
        ssc.configureBlocking(false);

        //监听新链接传入
        while (true){
            SocketChannel sc = ssc.accept();
            if(sc == null){
                Thread.sleep(2000);
            }else {
                System.out.println(sc.socket().getRemoteSocketAddress());
                bf.rewind();
                sc.write(bf);
                sc.close();
            }

        }
    }
}

socketChannel
面向TCP

public class io4 {
    public static void main(String[] args) throws IOException {
        SocketChannel sc = SocketChannel.open(new InetSocketAddress("www.baidu.com",80));

        sc.configureBlocking(false);
        ByteBuffer bf = ByteBuffer.allocate(100);
        sc.read(bf);
        sc.close();
        System.out.println("over");


    }
}

datagramChannel
面向UDP

public class io5 {

    public  void send() throws IOException, InterruptedException {
        DatagramChannel dc = DatagramChannel.open();
        InetSocketAddress ad = new InetSocketAddress("127.0.0.1",9999);
        while (true){
            ByteBuffer bf = ByteBuffer.wrap("jsjsjsj".getBytes());
            dc.send(bf,ad);
            System.out.println("发送");
            Thread.sleep(1000);
        }

    }

    public void receive() throws IOException {
        DatagramChannel dc = DatagramChannel.open();
        InetSocketAddress ad = new InetSocketAddress(9999);
        dc.bind(ad);
        ByteBuffer bf = ByteBuffer.allocate(1024);
        while (true){
            bf.clear();
            SocketAddress sc = dc.receive(bf);
            bf.flip();

            System.out.println(sc.toString() + bf);
        }



    }
}

channel的scatter和gather功能
在这里插入图片描述

在这里插入图片描述

Buffer

就是一块可以读写的内存空间,NIO中所有数据都用缓冲区处理

两种分配Buffer的方法:
ByteBuffer buf = ByteBuffer.allocate(10);
在堆中开辟,易于管理,垃圾回收器可以回收,空间有限,读写慢。

ByteBuffer buf2=ByteBuffer.allocateDirect(10);
物理内存中开辟空间,空间比较大,读写文件速度快,不受垃圾回收器控制。

buffer读写操作

public class io6 {
    public static void main(String[] args) throws IOException {
        buffer01();
    }

    public static void buffer01() throws IOException {
        RandomAccessFile ra = new RandomAccessFile("C:\\Users\\86158\\Desktop\\datax.txt","rw");
        FileChannel channel = ra.getChannel();
        ByteBuffer bf = ByteBuffer.allocate(1024);

        //读
        channel.read(bf);
        bf.flip();
        while (bf.hasRemaining()){
            System.out.println((char) bf.get());
        }
        bf.clear();


        //写
        for (int ii = 0; ii < bf.capacity();ii++){
            bf.put((byte) ii);
        }
        bf.flip();
        while (bf.hasRemaining()){
            System.out.println((char) bf.get());
        }
        bf.clear();

    }
}

buffer的属性 capacity position limit

capacity: 最多能写多少

position: 读写的当前位置,flip后变0

limit : 最多读到哪里(flip前的position)/最多写到哪里(capacity)

buffer放入数据两个方式

buffer.put()
channel.read(buffer)

buffer读数据
buffer.get()
channel.write(buffer)

rewind方法/flip方法

flip是写好了开始读,limit 要设成position,position变0

rewind是单纯position变0

clear方法/compact方法

clear: position设0
compact:准备好写数据了,未读过的数据不清除,未读数据拷贝到buffer起始处,position设为最后一个未读数据后面

mark方法/reset方法

mark标记特定position, reset恢复到这个position

buffer分片

在 NIO 中,除了可以分配或者包装一个缓冲区对象外,还可以根据现有的缓冲区对象
来创建一个子缓冲区,即在现有缓冲区上切出一片来作为一个新的缓冲区,但现有的
缓冲区与创建的子缓冲区在底层数组层面上是数据共享的,也就是说,子缓冲区相当
于是现有缓冲区的一个视图窗口。调用 slice()方法可以创建一个子缓冲区。

切片范围是调用slice方法时原始缓冲区的position到limit索引之间的数据

buffer只读

只读缓冲区非常简单,可以读取它们,但是不能向它们写入数据。可以通过调用缓冲
区的 asReadOnlyBuffer()方法,将任何常规缓冲区转 换为只读缓冲区,这个方法返
回一个与原缓冲区完全相同的缓冲区,并与原缓冲区共享数据,只不过它是只读的。
如果原缓冲区的内容发生了变化,只读缓冲区的内容也随之发生变化

区相当
于是现有缓冲区的一个视图窗口。调用 slice()方法可以创建一个子缓冲区。

切片范围是调用slice方法时原始缓冲区的position到limit索引之间的数据

buffer只读

只读缓冲区非常简单,可以读取它们,但是不能向它们写入数据。可以通过调用缓冲
区的 asReadOnlyBuffer()方法,将任何常规缓冲区转 换为只读缓冲区,这个方法返
回一个与原缓冲区完全相同的缓冲区,并与原缓冲区共享数据,只不过它是只读的。
如果原缓冲区的内容发生了变化,只读缓冲区的内容也随之发生变化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值