文档章节

Jetty源码-IO-BufferUtil

robin-yao
 robin-yao
发布于 2015/04/16 23:33
字数 837
阅读 578
收藏 29

    jetty 源码 BufferUtil 工具类主要是封装了对JDK ByteBuffer的操作。通过BufferUtil可以更容易的操作ByteBuffer.

由于ByteBuffer分为fill模式即写模式、flush模式即读模式,我们经常会在读写之间把ByteBuffer的状态搞混,经常忘记调用flip()等等,而且代码不容易理解。以后我们可以把jetty提供的BufferUitl引入作为工具类,很方便的操作ByteBuffer。如下示例:

 //置为写模式
  int pos = BufferUtil.flipToFill(buffer);
  try
  {        //写入数据
          buffer.put(data);
  }
  finally
  {        //置为读模式
          flipToFlush(buffer, pos);
  }

下面是贴出的部分BufferUitl代码,及个人的注释:

public class BufferUtil {

    /**
     * 分配flush模式的ByteBuffer,limit和position都为0,在写入数据时,必须先翻为fill模式
     * @param capacity
     * @return
     */
    public static ByteBuffer allocate(int capacity)
    {
        ByteBuffer buf = ByteBuffer.allocate(capacity);
        buf.limit(0);
        return buf;
    }
    public static ByteBuffer allocateDirect(int capacity)
    {
        ByteBuffer buf = ByteBuffer.allocateDirect(capacity);
        buf.limit(0);
        return buf;
    }

    /**
     * 清空buffer ,只需把positoin 和limit 同时置为0
     * @param buffer
     */
    public static void clear(ByteBuffer buffer)
    {
        if (buffer != null)
        {
            buffer.position(0);
            buffer.limit(0);
        }
    }

    /**
     * 清空buffer ,置为fill模式
     * @param buffer
     */
    public static void clearToFill(ByteBuffer buffer)
    {
        if (buffer != null)
        {
            buffer.position(0);
            buffer.limit(buffer.capacity());
        }
    }

    /**
     * 翻转为fill模式
     * @param buffer
     * @return
     */
    public static int flipToFill(ByteBuffer buffer)
    {
        int position = buffer.position();
        int limit = buffer.limit();
        //说明正好flush完,可以完全转换未fill模式
        if (position == limit)
        {
            buffer.position(0);
            buffer.limit(buffer.capacity());
            return 0;
        }
        //当前limit equal capacity,另申请空间
        int capacity = buffer.capacity();
        if (limit == capacity)
        {
            buffer.compact();
            return 0;
        }
        //一般情况,剩余的容量,可写的空间
        buffer.position(limit);
        buffer.limit(capacity);
        return position;
    }

    /**
     * 转为flush模式,即读模式,把当前写到的位置至为limit,动态传入读开始位置position,
     * 如果position未0 ,该方法的作用和 ByteBuffer.flip()的作用等价
     * @param buffer
     * @param position
     */
    public static void flipToFlush(ByteBuffer buffer, int position)
    {
        buffer.limit(buffer.position());
        buffer.position(position);
    }

    /**
     * 把buffer转换为数组。
     * @param buffer
     * @return
     */
    public static byte[] toArray(ByteBuffer buffer)
    {
        //主要针对heap buffer
        if (buffer.hasArray())
        {
            byte[] array = buffer.array();
            int from=buffer.arrayOffset() + buffer.position();
            return Arrays.copyOfRange(array, from, from + buffer.remaining());
        }
        //针对 direct buffer
        else
        {
            byte[] to = new byte[buffer.remaining()];
            buffer.slice().get(to);
            return to;
        }
    }

    /**
     * 是否为空 ,remaining() 主要是  limit - position
     * @param buf
     * @return
     */
    public static boolean isEmpty(ByteBuffer buf)
    {
        return buf == null || buf.remaining() == 0;
    }
    public static boolean hasContent(ByteBuffer buf)
    {
        return buf != null && buf.remaining() > 0;
    }
    public static boolean isFull(ByteBuffer buf)
    {
        return buf != null && buf.limit() == buf.capacity();
    }
    public static int length(ByteBuffer buffer)
    {
        return buffer == null ? 0 : buffer.remaining();
    }
    public static int space(ByteBuffer buffer)
    {
        if (buffer == null)
            return 0;
        return buffer.capacity() - buffer.limit();
    }
    public static boolean compact(ByteBuffer buffer)
    {
        if (buffer.position()==0)
            return false;
        boolean full = buffer.limit() == buffer.capacity();
        buffer.compact().flip();
        return full && buffer.limit() < buffer.capacity();
    }

    /**
     * 把from中未读的,写到 to 中
     * @param from Buffer  读模式  flush
     * @param to   Buffer  写模式  fill
     * @return number of bytes moved
     */
    public static int put(ByteBuffer from, ByteBuffer to)
    {
        int put;
        int remaining = from.remaining();
        if (remaining > 0)
        {   //如果空间足够,直接写入
            if (remaining <= to.remaining())
            {
                to.put(from);
                put = remaining;
                //把from 读完
                from.position(from.limit());
            }
            //heap buffer
            else if (from.hasArray())
            {
                put = to.remaining();
                //只读部分数据
                to.put(from.array(), from.arrayOffset() + from.position(), put);
                from.position(from.position() + put);
            }
            //direct buffer
            else
            {
                //只读部分数据
                put = to.remaining();
                ByteBuffer slice = from.slice();
                slice.limit(put);
                to.put(slice);
                from.position(from.position() + put);
            }
        }
        else
            put = 0;

        return put;
    }

    /** 添加 byte[] 到buffer中
     * @param to
     * @param b
     * @param off
     * @param len
     * @throws java.nio.BufferOverflowException
     */
    public static void append(ByteBuffer to, byte[] b, int off, int len) throws BufferOverflowException
    {   //置为写模式
        int pos = flipToFill(to);
        try
        {
            to.put(b, off, len);
        }
        finally
        {
            //置为读模式
            flipToFlush(to, pos);
        }
    }

    /**
     * 从文件中读数据到buffer中
      * @param file
     * @param buffer
     * @throws IOException
     */
    public static void readFrom(File file, ByteBuffer buffer) throws IOException
    {
        try(RandomAccessFile raf = new RandomAccessFile(file,"r"))
        {
            FileChannel channel = raf.getChannel();
            long needed=raf.length();

            while (needed>0 && buffer.hasRemaining())
                needed=needed-channel.read(buffer);
        }
    }

    public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
    {
        ByteBuffer tmp = allocate(8192);

        while (needed > 0 && buffer.hasRemaining())
        {
            int l = is.read(tmp.array(), 0, 8192);
            if (l < 0)
                break;
            tmp.position(0);
            tmp.limit(l);
            buffer.put(tmp);
        }
    }
}

转载请表明来源:http://my.oschina.net/robinyao/blog/402692  

END------------------------------------------

© 著作权归作者所有

共有 人打赏支持
robin-yao
粉丝 161
博文 54
码字总数 61436
作品 0
杭州
私信 提问
eclipse使用maven tomcat插件部署无法关联源代码

eclipse maven 起服务debug无法关联源码 博客分类: maven eclipse 1. 安装sourcelookup插件: update site: 1) http://bjmi.github.io/update-site/ (3.8.2可用,后续描述均针对此插件) 2) ht...

赵作文
2015/10/20
246
0
Jetty9 源码初解(2)——IO之EndPoint

一、概述 EndPoint作为jetty-io的一个重要组成部分,是基于javaNIO的封装,用于底层网络的读写,一旦网络读写准备好,会调用相应的connection的handle方法。 二、类分析 EndPoint源码如下: ...

戴的天
2015/10/28
0
0
从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一) 收藏 如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现...

光石头
2011/02/20
0
0
node npm install 报错

E:\angularJs2\angular2-seed-master>npm install > bufferutil@1.2.1 install E:\angularJs2\angular2-seed-master\node_modules\bufferutil > node-gyp rebuild E:\angularJs2\angular2-se......

guo_sunshine
2016/03/16
2.7K
0
从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现大伙都基于类似的方式,我感觉这应该算是NIO构架网络服务器的经典模式,...

山哥
2012/03/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Cookie 显示用户上次访问的时间

import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.serv......

gwl_
57分钟前
1
0
网络编程

第14天 网络编程 今日内容介绍  网络通信协议  UDP通信  TCP通信 今日学习目标  能够辨别UDP和TCP协议特点  能够说出UDP协议下两个常用类名称  能够说出TCP协议下两个常用类名称...

stars永恒
今天
1
0
二进制相关

二进制 众所周知计算机使用的是二进制,数字的二进制是如何表示的呢? 实际就是逢二进一。比如 2 用二进制就是 10。那么根据此可以推算出 5的二进制等于 10*10+1 即为 101。 在计算机中,负数以...

NotFound403
昨天
3
0
day22:

1、写一个getinterface.sh 脚本可以接受选项[i,I],完成下面任务: 1)使用格式:getinterface.sh [-i interface | -I ip] 2)当用户使用-i选项时,显示指定网卡的IP地址;当用户使用-I选项...

芬野de博客
昨天
2
0
Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

自Spring Cloud Alibaba发布第一个Release以来,就备受国内开发者的高度关注。虽然Spring Cloud Alibaba还没能纳入Spring Cloud的主版本管理中,但是凭借阿里中间件团队的背景,还是得到不少...

程序猿DD
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部