NIO入门篇——ByteBuffer

1、基本使用代码

  1. 向buffer写入数据,例如调用channelread(buffer)
  2. 调用flip()切换至读模式
  3. 从buffer读取数据,例如调用buffer.get()
  4. 调用clear() 或cornpact()切换至写模式
  5. 重复1-4
public static void main(String[] args) {
//        FileChannel
//        1、输入输出流  2.RandomAccessFile  data.txt
        try(FileChannel channel  = new FileInputStream("D:\\\\1zheng\\\\dai\\\\netty\\\\mode01\\\\data.txt").getChannel()){
//          准备缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(10);  //10个字节
            while (true) {
//                从channel 读取数据,向buffer写入
                int read = channel.read(buffer);
                log.debug("读取到的字节数:{}", read);
                if (read == -1) break; //没有内容时退出
                
//                打印内容
                buffer.flip();  //切换读模式
                while (buffer.hasRemaining()) {  //是否还有剩余数据
                    byte b = buffer.get();  
                    log.debug("实际字节:{}", (char) b);
                }
                buffer.clear();  //切换写模式
            }
        }catch (IOException e){

        }
    }

ByteBuffer有以下重要属性

  • capacity :容量
  • position : 读写下标
  • limit :读写限制

流程

 

2、ByteBuffer常见方法

分配空间

可以使用 allocate 方法为ByteBuffer分配内存,也可以使用*allocateDirect方法*

allocate :分配的是是java堆内存,读写效率低,受到GC的影响

allocateDirect:直接内存,读写效率高(少一次拷贝),不会受到GC的影响,分配的效率低

读写操作

clear() :从0下标开始写

cornpact():压缩已有的空间,从写入到的位置继续写

get():从position 位置开始读;

get(0):读取0下标的值;

rewind():把position 移动到0下标;

mark():标记当前position 下标

reset()position移动到mark()标记的下标去;

字符串转换

put("hello".getBytes());

StandardCharsets.UTF_8.encode("hello");

ByteBuffer.wrap("hello".getBytes());

public static void main(String[] args) {
//        1、字符串转为ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(16);

        buffer.put("hello".getBytes());    //该方法需要去手动转为读模式
        buffer.flip();
        System.out.println(buffer);
        System.out.println((char) buffer.get());

//        下面两种方法可以自动转为读模式
        ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
        System.out.println(buffer2);
        System.out.println((char) buffer2.get());

        ByteBuffer buffer1 = ByteBuffer.wrap("hello".getBytes());
        System.out.println(buffer1);
        System.out.println((char) buffer1.get());

//        2、把ByteBuffer转为字符串
        String s = StandardCharsets.UTF_8.decode(buffer2).toString();
        System.out.println(s);
    }

分散读取,集中写入到磁盘

public static void main(String[] args) {
    ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
    ByteBuffer buffer3 = StandardCharsets.UTF_8.encode("hello");
    ByteBuffer buffer4 = StandardCharsets.UTF_8.encode("你好");
    try(FileChannel channel = new RandomAccessFile("words2.txt","rw").getChannel()){
        channel.write(new ByteBuffer[]{buffer2,buffer3,buffer4});
    }catch (Exception e){}
}

解决网络编程中ByteBuffer常见的粘包,半包问题

public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put("Hello,world\\nI'm zhangsan\\nHo".getBytes());
        split(buffer);  //会先把粘包的读取完
        buffer.put("w are you?\\n".getBytes());
        split(buffer);   //最后在把半包的拼接读取掉
    }

    private static void split(ByteBuffer buffer) {
        buffer.flip();
        for (int i = 0; i < buffer.limit(); i++) {
//            通过\\n找到一条完整消息
            if (buffer.get(i)=='\\n'){
                int length = i+1-buffer.position();
//                  创建指定大小的缓冲区
                ByteBuffer target = ByteBuffer.allocate(length);
//                把完整数据写入新的ByteBuffer中
                for (int j = 0; j < length; j++) {
                    target.put(buffer.get());
                }
                target.flip();
                String s = StandardCharsets.UTF_8.decode(target).toString();
                System.out.println(s);
                System.out.println(buffer);
            }
        }
        buffer.compact();
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值