《Java程序性能优化》3.3 使用NIO提升性能(未完)

p:102-118

流与NIO的不同

流以字节为单位,NIO基于块(block)为单位。
channel是双向的通道。stream是单向的。

NIO组件

NIO两个重要组件:通道channel和缓冲buffer

通道表示缓冲数据的源头或者目的地。
缓冲是一块连续的内存, 是NIO读写数据的中转地。

通道(Channel)

不能直接对channel进行读写操作,必须通过Buffer来进行。
如: 在读一个Channel的时候,需要先将数据读入到相对应的Buffer,然后在Buffer中进行读取。
fc=fileInputStream.getChannel()

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//buffer初始化的时候,pos=0,limit=capacity
fc.read(byteBuffer)
fc.close();
byeBuffer.flip();//limit=pos;pos=0; 表示只能读pos--limit的内容

特别注意:
FileChannel outChannel = fileOutputStream.getChannel();
FileChannel inChannel = fileinputStream.getChannel();
inChannel.read(buff) 是 读取通道的内容buffer
outChannel.write(b)是将buffer中的内容(limit到pos位置)写到通道对应的位置

缓冲(Buffer)

Buffer基本参数

参数 说明
位置(position) 当前操作的位置,0<=position<=limit<=capacity
容量(capacity) 操作位置的最大值
上限(limit) 读/写操作的范围 ,0<=limit<=capacity

对Buffer的操作:clear、flip、rewind

注意:实际没操作数据,只是操作了limit,pos。三者都会清除mark。

**clear:**清除此缓冲区。将位置设置为 0,将限制设置为容量(limit=capacity),并丢弃标记(mark)。 :它将限制设置为容量大小,将位置设置为 0。 ps:变成初始状态,pos=0,limit=capcity=max

**flip:**使缓冲区为一系列新的通道写入或相对获取 操作做好准备。:反转此缓冲区。首先将限制设置为当前位置,然后将位置设置为 0。如果已定义了标记,则丢弃该标记。 。 ps:规定写入读取的最大limit,limit=position,position=0;

rewind: 使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为 0,并丢弃标记。 ps:position=0;丢弃掉上次pos修改。 所以可以重复读取

mark与reset

像书签一样, 方便快速恢复到标记的位置(position)。
mark:在此缓冲区的位置设置标记。
reset:改变position为之前标记的值

public final Buffer reset()将此缓冲区的位置重置为以前标记的位置。
调用此方法不更改也不丢弃标记的值。
返回:
此缓冲区
抛出:
InvalidMarkException - 如果尚未设置标记

待续。。

测试用例

package com.gkwind.nio;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Author thewindkee
 * @Date 2019/4/18 0018 下午 12:19
 */
public class NIOTest {
    public static void main(String[] args) throws IOException {
        testFlipAndRewind();
        testChannel();
        testMarkAndReset();

    }


    private static ByteBuffer prepareBuffer() {
        System.out.println("prepareBuffer");
        ByteBuffer b = ByteBuffer.allocate(15);//初始化,pos=0,limit=capacity
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=0
        for (int i = (int)'a'; i <(int)'a'+ 10; i++) {
            b.put((byte) i);
        }
        return b;
    }
    private static void testChannel() throws IOException {
        ByteBuffer b = prepareBuffer();
        b.get();
        // channel
        //limit=1
        File file = new File("a.txt");
        System.out.println(file.getAbsolutePath());
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        FileChannel outChannel = fileOutputStream.getChannel();
        outChannel.write(b);
//        fileOutputStream.flush();
        outChannel.close();
        //文件中 包含 bcdefghij
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=10

        File bfile = new File("b.txt");
        FileUtils.write(bfile, "中国", "UTF-8");//准备数据
        FileInputStream fileInputStream = new FileInputStream(bfile);
        FileChannel inChannel = fileInputStream.getChannel();
        //清空buffer
        b.clear();//pos=0,limit=capacity
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=0
        inChannel.read(b);
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
        b.flip();//确定limit位置,准备读
        System.out.println(new String(b.array(),b.position(),b.limit()));//中国
    }

    private static void testFlipAndRewind() {
        System.out.println("testFlipAndRewind");
        //rewind and flip
        ByteBuffer b = prepareBuffer();
//        b.put("中国".getBytes("GBK"));
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=10
        b.flip();//limit=pos,pos=0;定义能get/put的最大位置
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
        System.out.println("get...");
//        byte[] dst = new byte[1024];
//        b.get(dst,b.position(),b.limit());//会引起变化
//        System.out.println(dst.length+" "+new String(dst));//abcdefghij        注意包含了空格(1024-10个)
        byte [] des2 = new byte[b.limit()];
        b.get(des2);//会引起变化
        System.out.println(new String(des2));//abcdefghij
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=10
        System.out.println("rewind..");
        b.rewind();//丢弃掉pos变化,pos=0; limit不变;方便重新读取
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
        System.out.println(new String(b.array(), b.position(), b.limit()));//不会改变limit
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=0
        System.out.println(b.get());//limit++
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=10 capacity=15 position=1
    }
 


    private static void testMarkAndReset() {
        System.out.println("testMarkAndReset");
        //mark and reset
        ByteBuffer b = prepareBuffer();
        b.clear();
        for (int i = (int)'a'; i <(int)'a'+ 10; i++) {
            b.put((byte) i);
        }
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
        b.flip();
        System.out.println("flip... 准备读...");
        b.get();
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
        b.mark();
        System.out.println("mark...");
        b.get();
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
//        b.clear();//clear会清除mark的位置
        b.reset();
        System.out.println("reset...");
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
        b.limit(3);//会清除mark的位置
        System.out.println("limit(3)...");
        System.out.println("limit=" + b.limit() + " capacity=" + b.capacity() + " position=" + b.position());//limit=15 capacity=15 position=6
    }

}
原文地址:https://www.cnblogs.com/thewindkee/p/12873139.html