Java NIO之上

一、IO与NIO的区别
IO:面向流的、阻塞的
NIO:面向缓冲区的、非阻塞的、有选择器

二、NIO的核心:通道(Channel)和缓冲区(Buffer)
1、使用NIO:需要获取连接IO设备(如:文件、套接字)的通道和容纳数据的缓冲区;然后操作缓冲区,对数据进行处理。

Channel负责传输;Buffer负责存储;

三、缓冲区Buffer
1、定义:缓冲区主要是用来与通道交互的;从通道读取数据,向通道写入数据;缓冲区存储的是相同的基本数据类型,类似与数组;java.nio包下的类都是抽象类Buffer的子类;

ByteBuffer, ShortBuffer,IntBuffer, CharBuffer,FloatBuffer,DoubleBuffer,LongBuffer

2、基本属性:
容量 capacity:缓冲区的大小
限制 limit:从limit开始后的数据不可读写
位置 position:准备要读取或写入的索引
标记 mark 和重置 reset:mark是一个索引,通过 mark()方法指定一个特殊的position位置,之后可以通过调用 reset()方法 回到 该 position

注意: 0<=mark<=position<=limit<=capacity

3、主要方法:
static xxxBuffer allocate(int capacity): 创建xxx类型的Buffer
Buffer clear() :清空缓冲区
Buffer flip():将limit设置为当前位置,并将position置为0
int capacity() :返回Buffer容量大小
boolean hasRemaining() : 判断position和limit之间是否还有元素
int limit() :返回界限的位置
Buffer limit (int n) :将缓冲区界限设置为 n
Buffer mark() :在该位置设置标记
int position () :返回缓冲区当前位置
Buffer position () :将缓冲区当前位置设置为 n
int remaining () :返回position 和limit之间的元素个数
Buffer reset() :将缓冲区当前位置设置为之前mark标记处的位置
Buffer rewind() :将当前位置position设置为0,并清空设置的mark标记

获取Buffer中的数据:
get()
get (int[] arr)
get (int index) (不会移动position)

放入数据到Buffer中:
put()
put(int[] arr)
put(int index,int x)(不会移动position)

public class TestBuffer {
    public static void main(String[]args) {
        int[] array={1,2,3,4,5};  //创建一个数组
        IntBuffer buffer=IntBuffer.allocate(5);  //创建只能储存int类型的大小为5的缓冲区


            System.out.println(buffer.position());   //缓冲区创建时position位置为0
            System.out.println(buffer.limit());   //缓冲区创建时limit位置为5
    
            buffer.put(array);   //将数组里的值放入缓冲区
    
            System.out.println(buffer.position());  //此时position位置为5
            System.out.println(buffer.limit());  //此时limit仍然是5
    
            buffer.rewind();  //将缓冲区位置重新设置为0
            System.out.println(buffer.position());
    
            while(buffer.hasRemaining())   //判断position和limit之间是否有元素
                System.out.println(buffer.get());
            //注意:在position和limit处于同一位置时,调用get()会抛出异常BufferUnderflowException
    
            System.out.println("--"+buffer.get(1));
        }
    }

四、直接缓冲区和非直接缓冲区
1、通过allocate()方法建立非直接缓冲区,该缓冲区建立在JVM内存上
2、通过allocateDirect()方法建立直接缓冲区,该缓冲区建立在物理内存中

五、通道(Channel)
用于原节点与目标节点的连接;需要配合Buffer来进行数据传输;
主要的实现类: java.nio.channels.Channel 接口
FileChannel:用于读取、写入、映射、和操作文件的通道
SocketChannel :通过TCP来读取网络中数据的通道
ServerSocketChannel:通过监听新进来的TCP连接,对每一个新进来的连接都会创建一个ServerSocketChannel
DatagramChannel :通过UDP来读取网络中数据的通道

获取通道的方式:
1、java针对支持通道的类提供了getChannel () 方法
本地IO:FileInputStream 、 FileOutputStream 、RandomAcessFile
网络IO:Socket 、 ServerSocket 、 DatagramSocket

2、在JDK1.7中的NIO.2 针对各个方法提供了静态方法 open()
3、在JDK1.7中的NIO.2 的Files工具类的newByteChannel()

例如: 用FileInputStream 和 FileOutputStream 来创建只能输入或输出的通道

            //创建输入输出流
            FileInputStream in = new FileInputStream("./libs/6.jpg");
            FileOutputStream out = new FileOutputStream("./libs/1.jpg");

            //用getChannel()创建通道
            FileChannel inchannel = in.getChannel();
            FileChannel outchannel = out.getChannel();

            //创建非直接缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);   //使用allocateDiret()方法来创建直接缓冲区

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

                buffer.flip();  //将buffer切换成读取的模式

                outchannel.write(buffer);  //将缓冲区的数据写入通道

                buffer.clear();  //清空缓冲区

使用直接缓冲区俩复制文件(内存映射,缓冲区直接建立在物理内存上)

        //用FileChannel的静态方法来创建通道
     FileChannel inChannel=FileChannel.open(Paths.get("./libs/1.txt"), StandardOpenOption.READ);
     FileChannel outChannel=FileChannel.open(Paths.get("./libs/3.txt"),StandardOpenOption.WRITE,StandardOpenOption.READ);


     //创建通道大小的直接缓冲区
     MappedByteBuffer inmapbuffer=inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
     MappedByteBuffer outmapbuffer=outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());

     byte[] array=new byte[inmapbuffer.limit()];
     inmapbuffer.get(array);
     outmapbuffer.put(array);

     inChannel.close();
     outChannel.close();

五、分散与聚集
分散读取:将通道中的数据存入多个缓冲区中
聚集写入:将多个缓冲区中的数据聚集到通道中

六、字符集CharSet
编码:字符串->字节数组
解码:字节数组 ->字符串

1、打印所有的支持的字符集:

 Map<String,Charset> map=Charset.availableCharsets();  
        Set<String> set=map.keySet();

        for(String name:set)
            System.out.println(map.get(name)); 

2、编码:

        Charset charset=Charset.forName("UTF-8");  //使用UTF-8字符集
        CharsetEncoder encoder=charset.newEncoder();  //获取编码器
 
        CharBuffer charBuffer= CharBuffer.allocate(100);
        charBuffer.put("字符集");
        
        charBuffer.flip();
        
        ByteBuffer byteBuffer=encoder.encode(charBuffer); //编码

        for (int i=0;i<byteBuffer.limit();i++){
            System.out.println(byteBuffer.get());   //遍历并打印
        }

3、解码:

        Charset charset=Charset.forName("GBK");  //使用GBK字符集
        CharsetDecoder decoder=charset.newDecoder();   //解码器

        ByteBuffer byteBuffer=ByteBuffer.allocate(5);
        byte[] arr={9,2,3,4,5};
        byteBuffer.put(arr);

        byteBuffer.flip();  //将limit设置为当前位置,然后将position置为0

        CharBuffer charBuffer=decoder.decode(byteBuffer);  //解码
        for(int i=0;i<charBuffer.limit();i++)
            System.out.println(charBuffer.get());

猜你喜欢

转载自blog.csdn.net/Owen_L_Y/article/details/84995610