一步一步理解Java NIO(上)

Java NIO简介

Java NIO是从Java1.4版本开始引入的一个新的IO API,可以代替标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用方式完全不同,NIO是面向缓冲区的、基于通道的IO操作,NIO对文件的读写更加高效。

通道和缓冲区

Java NIO的核心在于通道(Channel)和缓冲区(Buffer)。通道表示IO设备(如文件、套接字等)的连接,Buffer用于存储数据。Buffer是所有缓冲区类的父类,数据从通道读入缓冲区,从缓冲区写入通道。Buffer有以下子类,如ByteBuffer,CharBuffer,ShortBuffer,IntBuffer……(8种基本类型除去Boolean)。
一步一步理解Java NIO(上)_第1张图片
常用函数测试如下:

package NIOTest;

import org.junit.Test;

import java.nio.ByteBuffer;

/**
 * Created by yangl on 2017/7/6.
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * FloatBuffer
 * DoubleBuffer
 * 通过allocate()获取缓冲区
 *
 * put()存入数据到Buffer
 * get()从Buffer中获得数据
 *
 * Buffer的4个核心属性
 * capacity: 表示缓冲区存储的最大容量,一旦声明便不能改变
 * limit:表示缓冲区可以操作的数据的大小,limit后的数据不能进行读写
 * position:正在操作的数据的位置
 * 0 <= position <= limit <= capacity
 *
 * 另外mark()可以记录position的位置,通过reset()恢复到mark()的位置
 */
public class BufferTest {

    @Test
    public void test2()
    {
        System.out.println("---------------mark()----------");
        String str = "abcde";
        ByteBuffer buf = ByteBuffer.allocate(1024);
        buf.put(str.getBytes());
        buf.flip();
        byte[] dst = new byte[buf.limit()];
        buf.get(dst,0,dst.length);
        System.out.println(buf.position());

        buf.flip();


        //mark()标记
        buf.mark();

        buf.get(dst,2,2);
        System.out.println(new String(dst,2,2));
        System.out.println(buf.position());

        //reset() 恢复到mark()的位置
        buf.reset();
        System.out.println(buf.position());

        //hasRemaining
        System.out.println("---------------hasRemaining()----------");
        if (buf.hasRemaining())
            System.out.println(buf.remaining());



    }


    @Test
    public void test1()
    {
        String str = "abcde";

        //1.分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        System.out.println("---------------allocate()----------");
        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());

        //put()方法测试
        buf.put(str.getBytes());System.out.println("---------------put()----------");
        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());

        //切换读取数据模式
        buf.flip();

        buf.put(str.getBytes());System.out.println("---------------flip()----------");
        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());


        //切换读取数据模式
        buf.flip();

        //get()方法测试
        System.out.println("---------------get()----------");
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println(new String(dst,0,dst.length));

        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());

        //rewing()可重复读
        System.out.println("---------------rewind()----------");
        buf.rewind();
        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());

        //clear()清空缓冲区,但是缓冲区中的数据依然存在,处在“被遗忘状态”,数据不正确
        System.out.println("---------------clear()----------");
        buf.clear();
        System.out.println(buf.capacity());
        System.out.println(buf.limit());
        System.out.println(buf.position());

        System.out.println(buf.get());
    }
}

直接缓冲区与非直接缓冲区

一步一步理解Java NIO(上)_第2张图片
一步一步理解Java NIO(上)_第3张图片
一步一步理解Java NIO(上)_第4张图片
直接缓冲区省略论文一次复制操作,运行速度加快,但是存在数据安全问题,而且物理内存映射文件的创建也需要一定的资源开销。如果需要数据长时间驻留在内存中,可以选择这种方式。

通道

一步一步理解Java NIO(上)_第5张图片
通道技术改进了传统的DMA处理方式,相当于一个完全独立的处理IO的处理器,处理大量数据时会有优势(不占用CPU)。
一步一步理解Java NIO(上)_第6张图片
fileChannel的常用方法:
一步一步理解Java NIO(上)_第7张图片
用通道完成文件复制:

package NIOTest;

import org.junit.Test;

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;

/**
 * Created by yangl on 2017/7/7.
 * 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。
 * Channel 本身不存储数据,因此需要配合缓冲区进行传输。
 *
 * 二、通道的主要实现类
 *  java.nio.channels.Channel 接口:
 *      |--FileChannel
 *      |--SocketChannel
 *      |--ServerSocketChannel
 *      |--DatagramChannel
 *
 * 三、获取通道
 * 1. Java 针对支持通道的类提供了 getChannel() 方法
 *      本地 IO:
 *      FileInputStream/FileOutputStream
 *      RandomAccessFile
 *
 *      网络IO:
 *      Socket
 *      ServerSocket
 *      DatagramSocket
 *
 * 2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open()
 * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel()
 *
 * 四、通道之间的数据传输
 * transferFrom()
 * transferTo()
 *
 * 五、分散(Scatter)与聚集(Gather)
 * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
 * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中
 *
 * 六、字符集:Charset
 * 编码:字符串 -> 字节数组
 * 解码:字节数组  -> 字符串
 */
public class ChannelTest {

    //利用通道完成文件复制
    @Test
    public void test1() throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        ByteBuffer buf = null;

        try{
            fis = new FileInputStream("C:\\MyCode\\Java\\JavaTest\\src\\NIOTest\\1.jpg");
            fos = new FileOutputStream("C:\\MyCode\\Java\\JavaTest\\src\\NIOTest\\2.jpg");
           //获取通道
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

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

           //将同道中的数据存入缓冲区
           while(inChannel.read(buf) != -1){
               buf.flip();//读数据模式
               outChannel.write(buf);
               //将缓冲区中的数据写入缓冲区中
               buf.clear();
           }
       }
       catch(Exception e)
       {
           e.printStackTrace();
       }
       finally {
            if (fis != null) {
                fis.close();
            }
            fos.close();
            buf.clear();
            inChannel.close();
            outChannel.close();
       }
    }

}

你可能感兴趣的:(Java核心-基础)