1. 程式人生 > >java核心學習(十八) javaNIO框架---“塊”模型的IO

java核心學習(十八) javaNIO框架---“塊”模型的IO

rac tag pmod 輸出流 decode 非阻塞 實際應用 byte channel

一、java新IO概述

  javaIO中的輸入流和輸出流都是通過字節的移動來處理的,面向流的輸入輸出系統一次只能處理一個字節,因此效率不高,而且傳統的輸入輸出流是阻塞試的,也就是說當無法讀到數據時,當前線程會被阻塞直到讀取到有效數據才會繼續運行。

  java1.4之後提供了一系列改進的輸入輸出類與方法,並且以NIO為基礎改寫了java.io包中的類,新增了滿足NIO的功能。

  NIO采用內存映射文件的方式,java.nio中主要的包有:

    java.nio ,主要包含於Buffer相關的類;

    java.nio.charset,主要包含字符集相關的類;

    java.nio.channels,主要包含Channel和Selector相關的類;

    java.nio.channels.spi,主要包含與Channel相關的服務提供者編程接口;

    java.nio.charset.spi,包含與字符集相關的服務提供者編程接口。

二、Buffer抽象類

  其子類有ByteBuffer(最常用)、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer,這些類沒有構造器,獲取buffer對象使用如下靜態方法:static XxxBuffer allocate(int capacity)。

  Buffer的幾個位置屬性:

  技術分享

  相應的兩個方法:clear(),let limit = capacity and position = 0,這相當於是為再次將數據寫入Buffer做好準備,

          flip(),let limit = position and position = 0 ,這相當於是為從Buffer中取出數據做好準備。

package NIOTest;

import java.nio.CharBuffer;

public class BufferTest {
    public static void main(String[] args)
    {
        CharBuffer buffer = CharBuffer.allocate(8);
        System.out.println("capacity:" +buffer.capacity());
        System.out.println(
"limit:" +buffer.limit()); System.out.println("position" + buffer.position()); buffer.put(‘a‘); buffer.put(‘b‘); buffer.put(‘c‘); System.out.println("加入三個元素後,position = " + buffer.position()); buffer.flip(); System.out.println("執行flip()後,limit = " + buffer.limit()); System.out.println("position = " + buffer.position()); //去除第一個元素 System.out.println("第一個元素(position=0):" + buffer.get()); System.out.println("取出第一個元素後,position = " + buffer.position()); //調用clear方法 buffer.clear(); System.out.println("執行clear()後,limit = " + buffer.limit()); System.out.println("執行clear()後,position = " + buffer.position()); System.out.println("執行clear()後,buffer內容並沒有被清除:" + "第三個元素為:"+ buffer.get(2)); System.out.println("執行絕對讀取後,position = " + buffer.position()); } }

  上面代碼嘗試了一下Buffer的使用,輸出為下

capacity:8
limit:8
position0
加入三個元素後,position = 3
執行flip()後,limit = 3
position = 0
第一個元素(position=0):a
取出第一個元素後,position = 1
執行clear()後,limit = 8
執行clear()後,position = 0
執行clear()後,buffer內容並沒有被清除:第三個元素為:c
執行絕對讀取後,position = 0

  上面程序使用的buffer是heapbuffer,每個heapbuffer在新建時都會創建一個對應的directbuffer,直接buffer的讀取效率高但是創建成本也高,具體buffer1的工作方式不在這裏深究= =,因為深究了沒有實際應用也會忘記。。

三、 Channel接口

  Channel用於與Buffer交互,實現數據的IO。

  java為Channel接口提供了DatagramChannel(支持UDP網絡通信)、FileChannel(文件讀寫)、Pipe.SinkChannel和Pipe.SourceChannel(支持線程間通信的管道)、SelectableChannel(可選擇阻塞與非阻塞的channel)、ServerSocketChannel和SocketChannel(支持TCP網絡通信)等等。

  Channel通過傳統的流節點來返回對應的Channel,常用的方法有map()、read()、write(),下面來試一試

  

package NIOTest;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class FileChannelTest {
    public static void main(String[] args) {
        File f = new File("./src/main/java/NIOTest/FileChannelTest.java");
        try (
                FileChannel inChannnel = new FileInputStream(f).getChannel();
                FileChannel outChannel = new FileOutputStream("a.txt").getChannel();

        ) {
            MappedByteBuffer buffer = inChannnel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            Charset charset = Charset.forName("GBK");
            outChannel.write(buffer);
            buffer.clear();
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer = decoder.decode(buffer);
            System.out.println(charBuffer);


        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

  下面代碼每次運行都會講a.txt文件的內容復制一份並將全部內容追加到該文件的後面

package NIOTest;

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

public class RandomFileChannelTest {
    public static  void mian (String[] args){
        File f= new File("a.txt");
        try(
                RandomAccessFile raf = new RandomAccessFile(f,"rw");
                FileChannel randomChannel = raf.getChannel();
                ){
            ByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY,0,f.length());
       //這裏移動的是channel的position,可以在任意位置將數據寫入channel。 randomChannel.position(f.length()); randomChannel.write(buffer); }
catch (IOException ioe){ ioe.printStackTrace(); } } }

四、Charset類

  字符集類主要用於文本格式數據編碼與解碼,具體用法在 三 中的第一個例子有所展示。

java核心學習(十八) javaNIO框架---“塊”模型的IO