Java NIO中的通道Channel(一)通道基礎

什麼是通道Channel

這個說實話挺難定義的,有點抽象,不過咱們能夠根據它的用途來理解;java

通道主要用於傳輸數據,從緩衝區的一側傳到另外一側的實體(如文件、套接字...),反之亦然;dom

通道是訪問IO服務的導管,經過通道,咱們能夠以最小的開銷來訪問操做系統的I/O服務;socket

順便說下,緩衝區是通道內部發送數據和接收數據的端點,以下圖所示;spa

另外,關於通道Channel接口的定義,很簡單,只有兩個方法,判斷通道是否打開和關閉通道;操作系統

public interface Channel extends Closeable {

    public boolean isOpen();

    public void close() throws IOException;

}

建立通道

通道主要分爲兩大類,文件(File)通道和套接字(socket)通道;線程

涉及的類有FileChannel類和三個socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel;code

下面分別看下這幾個通道是如何建立的:對象

建立FileChannel通道

FileChannel通道只能經過在一個打開的RandomAccessFile、FileInputStream或FileOutputStream對象上調用getChannel( )方法來獲取,以下所示:blog

        RandomAccessFile raf = new RandomAccessFile ("somefile", "r"); 
        FileChannel fc = raf.getChannel( );

建立SocketChannel通道

        SocketChannel sc = SocketChannel.open( ); 
        sc.connect (new InetSocketAddress ("somehost", someport));

建立ServerSocketChannel通道

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(somelocalport));

建立DatagramChannel通道

        DatagramChannel dc = DatagramChannel.open( );

使用通道

在使用通道的時候,咱們一般都將通道的數據取出存入ByteBuffer對象或者從ByteBuffer對象中獲取數據放入通道進行傳輸;繼承

在使用通道的過程當中,咱們要注意通道是單向通道仍是雙向通道,單向通道只能讀或寫,而雙向通道是可讀可寫的;

若是一個Channel類實現了ReadableByteChannel接口,則表示其是可讀的,能夠調用read()方法讀取;

若是一個Channel類實現了WritableByteChannel接口,則表示其是可寫的,能夠調用write()方法寫入;

若是一個Channel類同時實現了ReadableByteChannel接口和WritableByteChannel接口則爲雙向通道,若是隻實現其中一個,則爲單向通道;

如ByteChannel就是一個雙向通道,實際上ByteChannel接口自己並不定義新的API方法,它是一個彙集了所繼承的多個接口,並從新命名的便捷接口;

以下是一個使用通道的例子,展現了兩個通道之間拷貝數據的過程,已添加了完整的註釋:

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class Main
{

    public static void main(String[] args) throws IOException
    {
        ReadableByteChannel source = Channels.newChannel(System.in);
        WritableByteChannel dest = Channels.newChannel(System.out);
        channelCopy1(source, dest);
        // channelCopy2 (source, dest);
        source.close();
        dest.close();

    }

    private static void channelCopy1(ReadableByteChannel src, WritableByteChannel dest)
        throws IOException
    {
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        while (src.read(buffer) != -1)
        {
            // 切換爲讀狀態
            buffer.flip();
            // 不能保證所有寫入
            dest.write(buffer);
            // 釋放已讀數據的空間,等待數據寫入
            buffer.compact();
        }
        // 退出循環的時候,因爲調用的是compact方法,緩衝區中可能還有數據
        // 須要進一步讀取
        buffer.flip();
        while (buffer.hasRemaining())
        {
            dest.write(buffer);
        }
    }

    private static void channelCopy2(ReadableByteChannel src, WritableByteChannel dest)
        throws IOException
    {
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        while (src.read(buffer) != -1)
        {
            // 切換爲讀狀態
            buffer.flip();
            // 保證緩衝區的數據所有寫入
            while (buffer.hasRemaining())
            {
                dest.write(buffer);
            }
            // 清除緩衝區
            buffer.clear();
        }
        // 退出循環的時候,因爲調用的是clear方法,緩衝區中已經沒有數據,不須要進一步處理
    }

}

關閉通道

咱們能夠經過調用close()方法來關閉通道;

一個打開的通道表明與一個特定I/O服務的特定鏈接,並封裝該鏈接的狀態。當通道關閉時,這個鏈接會丟失,而後通道將再也不鏈接任何東西。

能夠經過isOpen()方法來判斷通道是否打開,若是對關閉的通道進行讀寫等操做,會致使ClosedChannelException異常;

另外,若是一個通道實現了InterruptibleChannel接口,那麼,當該通道上的線程被中斷時,通道會被關閉,且該線程會拋出ClosedByInterruptException異常;

參考資料

《Java NIO》

相關文章
相關標籤/搜索