NIO初识

本来想写Socket和Sersocket的非阻塞形式的,结果发现水平不足,还是先复习下NIO。

初识

Java NIO 由以下几个核心部分组成:

Channels
Buffers
Selectors

Channel 和 Buffer

基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。这里有个图示:
NIO初识_第1张图片

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。

这是在一个单线程中使用一个Selector处理3个Channel的图示:

NIO初识_第2张图片
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

buffer

Buffer的基本用法
1.写入数据到buffer
2.调用flip()方法
3.从buffer中读取数据
4.调用clear()或者compact()方法

为了理解Buffer的工作原理,需要熟悉它的三个属性:

capacity
position
limit
position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。
NIO初识_第3张图片
capacity

作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position

当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit

在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

//认识buffer  capacity(总容量) position(指针) limit(实际大小)
    //其他方法 mark()与reset()方法   标记和跳掉标记位置
    public static void  basebuffer() throws IOException{
    RandomAccessFile aFile = new RandomAccessFile("d://niotest/base.txt", "rw");
    FileChannel inChannel  = aFile.getChannel();

    ByteBuffer buf =ByteBuffer.allocate(2);
    int bytesRead = inChannel.read(buf);
    while(bytesRead != -1){
        buf.flip();//将buffer从读模式变为写模式  position变为0 limit变为position
        while(buf.hasRemaining()){
            System.out.println((char)buf.get());
        }
    buf.clear();
    bytesRead = inChannel.read(buf);//再读缓冲池那么多
    }
    aFile.close();
    }

从buffer写到channel

//从buffer写到channel
    public static void BufferTest(String data) throws IOException{
        RandomAccessFile inFile =new RandomAccessFile("d://niotest/buffer.txt","rw");
        Selector selector = Selector.open();
        FileChannel inChannel = inFile.getChannel();
        inChannel.write(ByteBuffer.wrap(new String(data).getBytes("utf-8")));
    }

分散 channel

//分散  channel 将数据分散到多个buffer中 
    public static void scatter() throws IOException{
        ByteBuffer head = ByteBuffer.allocate(6); 
        ByteBuffer body = ByteBuffer.allocate(20); 
        ByteBuffer [] bufferArray ={head,body};

        RandomAccessFile aFile = new RandomAccessFile("d://niotest/base.txt", "rw");
        FileChannel inChannel  = aFile.getChannel();
        long bytesRead = inChannel.read(bufferArray);
        while(bytesRead>-1){
            bufferArray[0].flip();
            while(bufferArray[0].hasRemaining()){
                System.out.println((char)bufferArray[0].get());
            }
            bufferArray[0].clear();
            bufferArray[1].flip();
            while(bufferArray[1].hasRemaining()){
                System.out.println((char)bufferArray[1].get());
            }
            bufferArray[1].clear();
            bytesRead  = inChannel.read(bufferArray);
        }

通道传输

//通道传输 如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel传到另一个channel
    public static void passStan() throws IOException{
        RandomAccessFile inFile =new RandomAccessFile("d://niotest/base.txt","rw");
        FileChannel inChannel = inFile.getChannel();

        RandomAccessFile outFile = new RandomAccessFile("d://niotest/lalala.txt", "rw");
        FileChannel outChannel = outFile.getChannel();

        long position = 0;
        long count = inChannel.size();
        System.out.println("count:"+count);
        outChannel.transferFrom(inChannel,position, count);
        //在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。
        //transferFrom() 其他的传输到file中  
        //transferTo() file传输到其他中
    }

你可能感兴趣的:(学习)