Java架构学习(九)NIO编程&直接缓冲区&非直接缓冲区&Buffer&make()&rest()&通道Channel&字符集Charset

NIO编程基础

一、什么是NIO编程?

    jdk1.4之后在IO的基础上进行改进的。
    NIO中有一个非阻塞IO,面向缓冲区的,NIO效率高。类似火车那种

    IO是阻塞IO:面向流的
    程序读取文件InputStream,类似水管一样传输。

NIO图示:

这里写图片描述

IO图示:

这里写图片描述

NIO和IO区别:

这里写图片描述

二、直接缓冲区与 非直接缓冲区

缓冲区分为两种:
直接缓冲去:
非直接缓冲区:
存放在物理内存比jvm缓冲区要快。

三、NIO(new IO)核心是通道+缓冲区(存放数据)

NIO:保留了IO本质操作读写操作,是非阻塞IO. 

这里写图片描述

NIO概念

这里写图片描述


四、使用buffer存储数据

Buffer可以用的类型有:
    byteBuffer
    LongBuffer
    IntegeBuffer
    FloatBuffer
    DoubleBuffer
三个参数:
    position:表示当前缓冲区操作的位置
    limit:表示当前缓冲区可用大小
    capacity:表示当前缓冲区的大小,定义好了就不可以变了

打印出buffer三个参数的案例:
package com.leeue.nio;

import java.nio.Buffer;
import java.nio.ByteBuffer;

import org.junit.Test;

/**
 * 
 * @classDesc: 功能描述:(这个是 NIO测试 缓冲区 buffer测试)
 * 缓冲区是 NIO 】提供给数据传输文件和通道是一起使用的,主要是存储数据。
 * Buffer:存放类型有   除了boolean
 * ByteBuffer 用的最多
 * LongBuffer
 * IntegerBuffer
 * FloatBuffer
 * DoubleBuffer
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月27日 下午5:28:37
 */
public class NioBufferDemo01 {
    /**
     * 三个参数
     * position:缓冲区正在操作的位置,默认从0开始
     * limit:缓冲区可用大小
     * capacity:表示缓冲区最大的容量,一旦声明不能改变
     * 
     * 核心方法:
     * put():往buffer存放数据
     * get():获取buffer数据
     */
    @Test
    public void test1() {
        //初始化byteBuffer大小
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.limit());//1024
        System.out.println(byteBuffer.capacity());//1024

        System.out.println("往buffer存放数据");
        byteBuffer.put("abcd1".getBytes());
        System.out.println(byteBuffer.position());//5
        System.out.println(byteBuffer.limit());//1024
        System.out.println(byteBuffer.capacity());//1024

        //要开启读取模式
        byteBuffer.flip();//将position 置为0  
        System.out.println("position:"+byteBuffer.position());

        System.out.println("读取数据....");

        byte[] bytes = new byte[byteBuffer.limit()];
        //将数据放到bytes里面
        byteBuffer.get(bytes);
        System.out.println(new String(bytes,0,bytes.length));
        System.out.println(byteBuffer.position());//
        System.out.println(byteBuffer.limit());//
        System.out.println(byteBuffer.capacity());//

        System.out.println("重复读取....");
        //只有设置下才能重复读 又会将position设置为上次postion的起始位置
        byteBuffer.rewind();

        byte[] bytes2 = new byte[byteBuffer.limit()];
        //将数据放到bytes里面
        byteBuffer.get(bytes2);
        System.out.println(new String(bytes2,0,bytes2.length));
        System.out.println(byteBuffer.position());//
        System.out.println(byteBuffer.limit());//
        System.out.println(byteBuffer.capacity());//

        //清空缓冲区,只是把数据下标重置了,数据还是在内存里,清空缓冲区又叫数据被遗忘
        System.out.println("清空缓存......");
        byteBuffer.clear();
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.limit());//1024
        System.out.println(byteBuffer.capacity());//1024

        System.out.println((char)byteBuffer.get());


    }
}

五、标记make与重置rest用法

package com.leeue.nio;

import java.nio.ByteBuffer;

/**
 * 
 * @classDesc: 功能描述:(Buffer中 make与rest方法)
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月30日 上午10:40:59
 */
public class NIOMakeAndRest {
    public static void main(String[] args) {

        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        String str = "abcd";
        byteBuffer.put(str.getBytes());
        // 开启读模式
        byteBuffer.flip();
        byte[] bytes = new byte[byteBuffer.limit()];
        byteBuffer.mark();//打印标记
        byteBuffer.get(bytes, 0, 2);
        System.out.println(new String(bytes, 0, 2));
        System.out.println(byteBuffer.position());

        System.out.println("---------重置--------");
        byteBuffer.reset();//这个重置就是将postion返回到mark上面去
        byteBuffer.get(bytes, 0, 2);
        System.out.println(new String(bytes, 0, 2));
        System.out.println(byteBuffer.position());
    }
}

六、缓冲区

缓冲区分为两种:
    第一种:直接缓冲区,存放在物理内存中  效率高 不需要来回拷贝
    第二种:非直接缓冲区:主要存放在jvm中 效率低 需要来回拷贝

存放在物理内存中比jvm缓冲区中快

非直接缓冲区

这里写图片描述

直接缓冲区

这里写图片描述

非直接缓冲区与直接缓冲区那种更安全?

非直接缓冲区更安全 
直接缓冲区占内存

七、通道(Channel)的原理获取


案例代码
package com.leeue.nio;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;

/**
 * 
 * @classDesc: 功能描述:(实际操作直接缓冲区与非直接缓冲区比较)
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月30日 上午11:11:29
 */
public class NIOChannelDemo03 {
    /**
     * 非直接缓冲区读写操作
     * @throws IOException 
     */
    @Test
    public void test01() throws IOException {
        //读入流
        FileInputStream fileInputStream = new FileInputStream("1.png");
        //写入流
        FileOutputStream fileOutputStream = new FileOutputStream("1Copy.png");
        //创建通道  读入流通道
        FileChannel inchannel = fileInputStream.getChannel();

        //创建写入流通道
        FileChannel outchannel = fileOutputStream.getChannel();

        //分配指定大小缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);//非直接缓冲区

        while(inchannel.read(buf)!=-1) {
            //开启读取模式
            buf.flip();
            //将数据写入到通道中
            outchannel.write(buf);
            //要clear,否则buf一直有数据,一直在读取 陷入死循环中
            buf.clear();

        }

        //关闭通道、关闭连接
        inchannel.close();
        outchannel.close();
        fileInputStream.close();
        fileOutputStream.close();
    }
    /**
     * 直接缓冲区操作
     * @throws IOException 
     */
    @Test
    public void test02() throws IOException{
        //创建读取管道
        FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
        //创建写入管道
        FileChannel outChannel = FileChannel.open(Paths.get("1CP.png"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        //定义映射文件
        MappedByteBuffer inMappedByte = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMappedByte = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
        //直接对缓冲区操作

        byte[] dsf = new byte[inMappedByte.limit()];
        inMappedByte.get(dsf);
        outMappedByte.put(dsf);

        inChannel.close();
        outChannel.close();
        System.out.println("直接缓冲区操作完毕");
    }
}

八、分散读取聚集写入

package com.leeue.nio;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 
 * @classDesc: 功能描述:(分散读取 聚集写入)
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月30日 上午11:53:49
 */
public class NIOScatteringDemo04 {
    public static void main(String[] args) throws IOException{


            // 随机访问
            RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
            // 获取通道
            FileChannel channel = raf.getChannel();
            // 分配指定大小指定缓冲区
            ByteBuffer buffer1 = ByteBuffer.allocate(100);
            ByteBuffer buffer2 = ByteBuffer.allocate(1024);
            // 分散读取
            ByteBuffer[] buffers = { buffer1, buffer2 };
            //读取,这个是入去。没有这个读取不了内容
            channel.read(buffers);
            for (ByteBuffer byteBuffer : buffers) {
                // 切换成读模式
                byteBuffer.flip();
            }
            // 获取通道
            System.out.println(new String(buffers[0].array(), 0, buffers[0].limit()));
            System.out.println("*****************");
            System.out.println(new String(buffers[1].array(), 1, buffers[1].limit()));

            System.out.println("聚集读取.....");
            RandomAccessFile raf2 = new RandomAccessFile("test2.txt", "rw");
            // 获取通道
            FileChannel channel2 = raf2.getChannel();
            channel2.write(buffers);
            raf2.close();
            raf.close();

    }
}

九、字符集Charset

编码:字符串-->字节数组
解码:字节数组-->字符串
package com.leeue.nio;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

/**
 * 
 * @classDesc: 功能描述:(字符编码案例)
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月30日 下午1:51:17
 */
public class CharsetDemo05 {
    public static void main(String[] args) throws CharacterCodingException {
        //获取编码器
        Charset charset = Charset.forName("GBK");
        CharsetEncoder ce = charset.newEncoder();
        //获取解码器
        CharsetDecoder cd = charset.newDecoder();
        CharBuffer charBuffer = CharBuffer.allocate(1024);
        charBuffer.put("欢迎访我的博客");
        charBuffer.flip();

        //编码
        ByteBuffer buffer = ce.encode(charBuffer);
        //这里打印出来的是加密后的字符串,需要进行解码才能转换
        System.out.println("****加密后的字符串****");
        for(int i = 0; i < 12; i++) {
            System.out.println(buffer.get());
        }
        //解码
        buffer.flip();
        //解密
        CharBuffer decode = cd.decode(buffer);
        System.out.println(decode.toString());

    }
}

猜你喜欢

转载自blog.csdn.net/leeue/article/details/81234937
今日推荐