您当前的位置: 首页 > 

庄小焱

暂无认证

  • 3浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Netty——Channel的原理与实战

庄小焱 发布时间:2021-10-28 20:22:04 ,浏览量:3

摘要

NIO的通道类似于流,但有些区别如下:

  • 通道可以同时进行读写而流只能读或者只能写
  • 通道可以实现异步读写数据。
  • 通道可以从缓种读数据,也可以写数据到缓冲:
  • BIO中的stream是单向的,例如 FilelnputStream对象只能进行读取数据的操作,NIO中的通道(Channel)是双向的,可以读操作,也可以写操作。
  • Channel在NIO中是一个接口public interface Channel extends Closeable0常用的 Channel类有:FileChanng,DatagramChannel、ServerSocketChannel 和SocketChannel。
  • FileChannel用于文件的数据读写,DatagramChannel用于UDP的数据读写,ServerSocketChannel和 SocketChannel用于TCP的数据读写。

Channel的主要函数 FileChannel

主要用来对本地文件进行IO操作,常见的方法有

  • 1) public int read(ByteBuffer dst从通道读取数据并放到缓净中
  • 2) public int write(ByteBuffer src),把缓冲区的数据写到通道中
  • 3) public long transferFrom(ReadableByteChannel src, long position, long count),目标通道中复制数据到当前通道
  • 4) public long transferTo(long position, long count, WritableByteChannel target),把数据从当前通道复制给目标通道
将数据写入到文件中
package com.zhuangxiaoyan.nio.channel;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Classname NIOFileChannel
 * @Description TODO
 * @Date 2021/10/28 23:39
 * @Created by xjl
 */
public class NIOFileChannel {

    public static void main(String[] args) throws IOException {
        String str="hi 庄小焱";
        //创建一个输出流->channel
        String filepath="D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\test";
        FileOutputStream fileOutputStream = new FileOutputStream(filepath);
        //通过FileOutputStream获取一个
        // FileChannel的真实的类型是FileChannelImpl 类型
        FileChannel fileChannel = fileOutputStream.getChannel();
        //创建一个buffer
        ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
        //数据放入到buffer
        byteBuffer.put(str.getBytes());
        //对bytebuffer 进行的flip
        byteBuffer.flip();
        //将bytebuffer的数据写入到filechannel
        fileChannel.write(byteBuffer);
        //关闭
        fileOutputStream.close();
    }
}
将文件数据读取出来
package com.zhuangxiaoyan.nio.channel;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Classname NIOFileChannel2
 * @Description 将文件的数据读取到控制台
 * @Date 2021/10/30 14:29
 * @Created by xjl
 */
public class NIOFileChannel2 {

    public static void main(String[] args) throws IOException {
        String filepath = "D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\test.txt";
        //创建文件的输入流
        File file = new File(filepath);
        FileInputStream fileInputStream = new FileInputStream(file);
        //通过fileinputStream  获取filechannel-->>实际类型的 FilechannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();
        //创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
        //将通道的数据读入到buffer
        fileChannel.read(byteBuffer);

        //将bytebuffer中的字节数据转为string
        System.out.println(new String(byteBuffer.array()));
    }
}
利用Buffer将文件读出在将数据写入到文件
package com.zhuangxiaoyan.nio.channel;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Classname NIOFileChannel3
 * @Description TODO
 * @Date 2021/10/30 14:39
 * @Created by xjl
 */
public class NIOFileChannel3 {
    public static void main(String[] args) throws IOException {

        File file = new File("D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\1.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        FileChannel fileChannel1 = fileInputStream.getChannel();

        File file1 = new File("D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\2.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file1);
        FileChannel fileChanne2 = fileOutputStream.getChannel();

        //创建一个bytebuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        while (true) {
            //这个有一个复位的操作 清空buffer
            byteBuffer.clear();
            int read = fileChannel1.read(byteBuffer);
            if (read == -1) {
                //表示读取完成
                break;
            }
            //将buffer中的数据写入到filechannel2---2.txt
            byteBuffer.flip();
            fileChanne2.write(byteBuffer);
        }
        //关闭相关的流
        fileInputStream.close();
        fileOutputStream.close();
    }
}
利用Transform完成文件的拷贝
package com.zhuangxiaoyan.nio.channel;

import java.io.*;
import java.nio.channels.FileChannel;

/**
 * @Classname NIOFileChannel4
 * @Description TODO
 * @Date 2021/10/30 14:55
 * @Created by xjl
 */
public class NIOFileChannel4 {

    public static void main(String[] args) throws IOException {
        File file=new File("D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\微信图片_20210422220149.jpg");
        FileInputStream fileInputStream=new FileInputStream(file);

        File file1=new File("D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\new copy.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream(file1);

        //获取各个流对应的filechannel
        FileChannel source=fileInputStream.getChannel();
        FileChannel dastch=fileOutputStream.getChannel();

        //使用的transferform完成拷贝
        dastch.transferFrom(source,0,source.size());

        //关闭相关的流
        source.close();
        dastch.close();

        fileInputStream.close();
        fileOutputStream.close();
    }
}
ReadOnlyBuffer函数
package com.zhuangxiaoyan.nio.channel;

import java.nio.ByteBuffer;

/**
 * @Classname NIOFileChannel5
 * @Description TODO
 * @Date 2021/10/30 15:05
 * @Created by xjl
 */
public class NIOFileChannel5 {
    public static void main(String[] args) {
        //创建一个buffer
        ByteBuffer buffer = ByteBuffer.allocate(64);
        for (int i = 0; i < 64; i++) {
            buffer.put((byte) i);
        }
        //读取
        buffer.flip();
        // 得到一个只读取的buffer
        ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
        System.out.println(readOnlyBuffer.getClass());

        while (readOnlyBuffer.hasRemaining()) {
            System.out.println(readOnlyBuffer.get());
        }
        //报错 将不允许写入数据
        readOnlyBuffer.put((byte)100);
    }
}
MappedByteBuffer函数
package com.zhuangxiaoyan.nio.channel;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Classname NIOFileChannel6
 * @Description mappedbyteBuffer 可以让文件直接修改(堆外内存) 操作系统不需要拷贝
 * @Date 2021/10/30 15:11
 * @Created by xjl
 */
public class NIOFileChannel6 {
    public static void main(String[] args) throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\softwaresavfile\\Github\\JAVA_NIO\\NIO\\src\\main\\resources\\1.txt", "rw");
        //获取对应的文件通道
        FileChannel channel = randomAccessFile.getChannel();
        /**
         参数l:Filechannel.MapMode.READ_WRITE使用的读写模式
         参数2:0 :可以直接修改的起始位置
         参数3:5:是映射到内存的大小 不是包含5的相当于是【0,5)
         */
        MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
        map.put(0, (byte) 'S');
        map.put(3, (byte) 'M');
        //关闭文件流
        randomAccessFile.close();
        //提示
        System.out.println("修改成功");
    }
}
Buffer gathering 和 scatter函数
package com.zhuangxiaoyan.nio.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

/**
 * @Classname NIOFileChannel7
 * @Description Scattering :buffer的分散和聚合 将数据写入到buffer时候 可以采用buffer数组 然后在依次写入
 * Gathering  :从buffer读取数据的时候 可以采用buffer数组 然后在依次读取
 * @Date 2021/10/30 15:23
 * @Created by xjl
 */
public class NIOFileChannel7 {

    public static void main(String[] args) throws IOException {
        //使用serversockerChannel 和SocketChannel网络
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);
        //绑定端口socket 并启动
        serverSocketChannel.socket().bind(inetSocketAddress);

        //创建buffer数组
        ByteBuffer[] byteBuffers = new ByteBuffer[2];

        byteBuffers[0] = ByteBuffer.allocate(5);
        byteBuffers[1] = ByteBuffer.allocate(3);
        //等待客户通知
        SocketChannel socketChannel = serverSocketChannel.accept();

        int messagelen = 8;

        //循环读取
        while (true) {
            int byteRead = 0;
            while (byteRead < messagelen) {
                long num = socketChannel.read(byteBuffers);
                byteRead += num;
                System.out.println("byteRead=" + byteRead);
                //使用的流打印 当前的buffer 和position和limit
                Arrays.asList(byteBuffers).stream().map(buffer -> "position" + buffer.position() + ", limit-" + buffer.limit()).forEach(System.out::println);
            }
            //将所有的buffer进行flip
            Arrays.asList(byteBuffers).forEach(byteBuffer -> byteBuffer.flip());
            //将数据的读取到客户端
            long bytewrite = 0;
            while (bytewrite < messagelen) {
                long num = socketChannel.write(byteBuffers);
                bytewrite += num;
            }
            //将所有的buffer 进行分析clear
            Arrays.asList(byteBuffers).forEach(byteBuffer -> byteBuffer.clear());
            System.out.println("byteRead" + byteRead + "byteWrite" + bytewrite);
        }
    }
}
Buffer和 Channel的区别
  • 1) ByteBuffer 支持类型化的put和 get, put放入的是什么数据类型,get就应该使用相应的数据类型来取出,否则可能有BufferUnderflowException异常。
  • 2)可以将一个普通Buffer转成只读Buffer
  • 3)NIO还提供了MappedByteBuffer,可以让文件直接在内存(堆外的内存)中进行修改,而如何同步到文件由NIO 来完成.
  • 4)前面我们讲的读写操作,都是通过一个Buffer完成的,NIO还支持通过多个Buffer(即 Buffer数组)完成读写操作,即 Scattering 和 Gatering
关注
打赏
1657692713
查看更多评论
立即登录/注册

微信扫码登录

0.0381s