NIO中Buffer与Channel搭配使用原理

Channel:用于源节点与目标节点之间的连接。在Java NIO中,负责缓冲区中数据传输,Channel本身不存储数据,因此需要配合缓冲区进行传输。
在NIO中,使用通道(Channel)基于缓冲区数据块的读写。

Buffer
ByteBuffer
CharBuffer
DoubleBuffer...
主要介绍一下ByteBuffer

ByteBuffer继承于Buffer类,ByteBuffer是个抽象类,它有两个实现的子类HeapByteBuffer和MappedByteBuffer类
HeapByteBuffer:在堆中创建的缓冲区。就是在jvm中创建的缓冲区。
MappedByteBuffer:直接缓冲区。物理内存中创建缓冲区,而不在堆中创建。

allocate 方法(创建堆缓冲区)

public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
}
allocate方法创建的缓冲区是创建的HeapByteBuffer实例。
HeapByteBuffer(int cap, int lim) {            // package-private
    super(-1, 0, lim, cap, new byte[cap], 0);
}
从堆缓冲区中看出,所谓堆缓冲区就是在堆内存中创建一个byte[]数组。
allocateDirect创建直接缓冲区
public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity);
}
我们发现allocate方法创建的缓冲区是创建的DirectByteBuffer实例。
直接缓冲区是通过java中Unsafe类进行在物理内存中创建缓冲区。

与Channel的配合使用
package com.expgiga.NIO;

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

/**
 * 一、Channel:用于源节点与目标节点之间的连接。在Java NIO中,负责缓冲区中数据传输,Channel本身不存储数据,因此需要配合缓冲区进行传输。
 *
 * 二、Channel的实现类:
 *     java.nio.channels.Channel 接口:
 *     |-- FileChannel
 *     |-- SocketChannel
 *     |-- ServerSocketChannel
 *     |-- DatagramChannel
 *
 * 三、获取通道Channel
 * 1.Java针对支持通道的类提供了getChannel()方法
 *   本地IO
 *   FileInputStream/FileOutputStream
 *   RandomAccessFile
 *
 *   网络IO:
 *   Socket
 *   ServerSocket
 *   DatagramSocket
 *
 * 2.在jdk1.7中的NIO.2针对各个通道提供了静态方法open()
 *
 * 3.在jdk1.7中的NIO.2的Files工具类的newByteChannel()
 *
 * 四、通道之间的数据传输
 * transferFrom()
 * transferTo()
 *
 */
public class TestChannel {

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

        /*
         * 1.利用通道完成文件的复制(非直接缓冲区)
         */
        FileInputStream fis = null;
        FileOutputStream fos = null;

        FileChannel inChannel = null;
        FileChannel outChannel = null;

        try {
            fis = new FileInputStream("1.jpg");
            fos = new FileOutputStream("2.jpg");
            //1.获取通道
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

            //2.分配指定大小的缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            //3.将通道中的数据缓冲区中
            while (inChannel.read(buffer) != -1) {

                buffer.flip();//切换成都数据模式

                //4.将缓冲区中的数据写入通道中
                outChannel.write(buffer);
                buffer.clear();//清空缓冲区
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


        /*
         * 2.利用(直接缓冲区)通道完成文件的复制(内存映射文件的方式)
         */

        long start = System.currentTimeMillis();
        FileChannel inChannel2 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel2 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

        //内存映射文件
        MappedByteBuffer inMappedBuf = inChannel2.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMappedBuf = outChannel2.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

        //直接对缓冲区进行数据读写操作
        byte[] dst = new byte[inMappedBuf.limit()];
        inMappedBuf.get(dst);
        outMappedBuf.put(dst);

        inChannel2.close();
        outChannel2.close();

        long end = System.currentTimeMillis();
        System.out.println("耗费的时间为:" + (end - start));

        /*
         * 通道之间的数据传输(直接缓冲区)
         */
        FileChannel inChannel3 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel3 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

        inChannel3.transferTo(0, inChannel3.size(), outChannel3);
        //等价于
//        outChannel3.transferFrom(inChannel3, 0, inChannel3.size());

        inChannel3.close();
        outChannel3.close();
    }
}


 

你可能感兴趣的:(IO)