Java NIO中的通道Channel(一)通道基礎。本站提示廣大學習愛好者:(Java NIO中的通道Channel(一)通道基礎)文章只能為提供參考,不一定能成為您想要的結果。以下是Java NIO中的通道Channel(一)通道基礎正文
這個說實話挺難定義的,有點抽象,不過我們可以根據它的用途來理解;
通道主要用於傳輸數據,從緩沖區的一側傳到另一側的實體(如文件、套接字...),反之亦然;
通道是訪問IO服務的導管,通過通道,我們可以以最小的開銷來訪問操作系統的I/O服務;
順便說下,緩沖區是通道內部發送數據和接收數據的端點,如下圖所示;

另外,關於通道Channel接口的定義,很簡單,只有兩個方法,判斷通道是否打開和關閉通道;
public interface Channel extends Closeable {
public boolean isOpen();
public void close() throws IOException;
}
創建通道
通道主要分為兩大類,文件(File)通道和套接字(socket)通道;
涉及的類有FileChannel類和三個socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel;
下面分別看下這幾個通道是如何創建的:
創建FileChannel通道FileChannel通道只能通過在一個打開的RandomAccessFile、FileInputStream或FileOutputStream對象上調用getChannel( )方法來獲取,如下所示:
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》