NIO Buffer中各重要状态属性的含义与关系以及源码解析(三)

我们解读一下 DirectByteBuffer的父类 MappedByteBuffer


解释: 一个直接的缓冲区,一个文件内存的映射区域

 是通过FileChannel#map来实现,是允许java程序直接从内存访问的特殊的文件,将整个文件 或者部分文件 映射到内存当中,由操作系统将内存的修改写入到文件中,我们的应用程序只需操作内存数据 进行迅速的IO操作,用于内存映射文件的内存本身 是在java堆的外面也是就堆外内存。

/**
 * A direct byte buffer whose content is a memory-mapped region of a file.
 *
 * <p> Mapped byte buffers are created via the {@link
 * java.nio.channels.FileChannel#map FileChannel.map} method.  This class
 * extends the {@link ByteBuffer} class with operations that are specific to
 * memory-mapped file regions.
 *
 * <p> A mapped byte buffer and the file mapping that it represents remain
 * valid until the buffer itself is garbage-collected.
 *
 * <p> The content of a mapped byte buffer can change at any time, for example
 * if the content of the corresponding region of the mapped file is changed by
 * this program or another.  Whether or not such changes occur, and when they
 * occur, is operating-system dependent and therefore unspecified.
 *
 * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become
 * inaccessible at any time, for example if the mapped file is truncated.  An
 * attempt to access an inaccessible region of a mapped byte buffer will not
 * change the buffer's content and will cause an unspecified exception to be
 * thrown either at the time of the access or at some later time.  It is
 * therefore strongly recommended that appropriate precautions be taken to 
 * avoid the manipulation of a mapped file by this program, or by a
 * concurrently running program, except to read or write the file's content.
 *
 * <p> Mapped byte buffers otherwise behave no differently than ordinary direct
 * byte buffers. </p>
 *
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class MappedByteBuffer
    extends ByteBuffer

举个栗子:

public class NioTest7 {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        RandomAccessFile randomAccessFile = new RandomAccessFile("NioTest9.txt","rw");

        FileChannel fileChannel = randomAccessFile.getChannel();

        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
	//只需操作内存 不需要写入文件 怎么把数据写入文件当中 都是由操作系统来完成 不需要我们去管
        mappedByteBuffer.put(0,(byte)'a');

        mappedByteBuffer.put(3,(byte)'b');

        randomAccessFile.close();
    }

}

下面我们来说 文件锁

public class NioTest8
{

    public static void main(String[] args) throws  IOException {

        RandomAccessFile randomAccessFile = new RandomAccessFile("NioTest9.txt","rw");

        FileChannel fileChannel = randomAccessFile.getChannel();
         //1.位置 2多长 3 ture是否是共享锁 false 排他锁
        FileLock fileLock =  fileChannel.lock(3,6,true);
        // 是否是有效的
        System.out.println("valid :"+fileLock.isValid());
        // 锁的类型是否是共享锁
        System.out.println("lock type :" +fileLock.isShared());
        fileLock.release();

        randomAccessFile.close();

    }
}


关于Buffer的Scattering与Gathering:

Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作。

分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。

聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel。

scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体.

之前我们read或write都是操作一个buffer 装满之后重新定义position位置重新在往里面读或写,而Scattering 不仅可以传一个buffer 还可以传buffer数组 比如我们一个buffer[0] 长度2  buffer[1] 长度5    buffer[2] 长度9,只有把第一个读满 在去读第二个,而Gathering 写也可以传buffer数组。

那么什么时候会这么使用呢:

比如我们在网络操作的时候 自定义协议 第一个传递过来的请求数据 第一个 buffer[1] 长度5   buffer[2] 长度9 作为Header buffer[3] 作为 Body 


举个栗子:

 

package nio;

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

/**
 * 关于Buffer的Scattering与Gathering
 */
public class NioTest9 {
    public static void main(String[] args) throws IOException{
        ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();

        InetSocketAddress address = new InetSocketAddress(8899);

        serverSocketChannel.socket().bind(address);

        int messageLenth = 2 + 3 +4;

        ByteBuffer[] buffers = new ByteBuffer[3];

        buffers[0] = ByteBuffer.allocate(2);
        buffers[1] = ByteBuffer.allocate(3);
        buffers[2] = ByteBuffer.allocate(4);

       SocketChannel socketChannel = serverSocketChannel.accept();

        while (true){
            int byteRead = 0;
            // 如果读到的字节数小于总的 继续读
            while (byteRead <messageLenth){
                long r = socketChannel.read(buffers);

                byteRead += r;

                System.out.println("byteRead :"+byteRead);

                Arrays.asList(buffers).stream().map(buffer -> "position:"+ buffer.position()+",limit"+buffer.limit()).forEach(System.out::println);
            }

            Arrays.asList(buffers).forEach(buffer ->{
                buffer.flip();
            });

            long bytesWritee =0;
            while (bytesWritee < messageLenth){
               long r = socketChannel.write(buffers);
                bytesWritee +=r;
            }

            Arrays.asList(buffers).forEach(buffer ->{
                buffer.clear();
            });

            System.out.println("byteRead :"+byteRead+ ",bytesWritee:"+bytesWritee+",messageLenth:"+messageLenth);
        }

    }
}


我们使用telnet localhost 8899

输入hellowor+回车 正好是9个字节

byteRead :9
position:2,limit2
position:3,limit3
position:4,limit4
byteRead :9,bytesWritee:9,messageLenth:9

如果输入 hello+回车 是6个字节

byteRead :6
position:2,limit2
position:3,limit3
position:1,limit4







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值