日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java NIO之通道

發布時間:2024/10/12 java 84 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java NIO之通道 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 通道
    • 通道基礎
      • 通道打開
      • 通道使用
      • 通道關閉
    • Scatter/Gather
    • 文件通道
      • 文件通道代碼示例
    • Socket通道
      • Socket通道代碼示例
    • 總結

通道

channel用于字節緩沖區和位于通道另一側的實體(通常是一個文件或套接字)之間有效的傳輸數據。
通道時一種途徑,通過這種途徑,可以用最小的總開銷來訪問操作系統本身的IO服務,緩沖區則是通道內部用于發送和接受數據的斷點。

通道基礎

頂層接口Channel,次級接口WritableByteChannel、ReadableByteChannel、InterruptibleChannel等。描述通道行為的接口在java.nio.channels包中定義,具體的通道實現都是從java.nio.channels.spi中的類引申來的。

通道打開

IO可以分為廣義的兩大類:File IO和Stream IO,對應File通道和Socket通道。體現在FileChannel類和三個socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel。
代碼如下:

//打開SocketChannelSocketChannel sc = SocketChannel.open( );sc.connect (new InetSocketAddress("somehost", port));//打開ServerSocketChannelServerSocketChannel ssc = ServerSocketChannel.open( );ssc.socket( ).bind (new InetSocketAddress (port));DatagramChannel dc = DatagramChannel.open( );//FileChannel只能通過 RandomAccessFile、FileInputStream 或 FileOutputStream 對象上調用 getChannel( )方法來獲取RandomAccessFile raf = new RandomAccessFile ("somefile", "r");FileChannel fc = raf.getChannel( );

通道使用

利用通道,從控制臺接收輸入,并在控制臺打印出接收的輸入。代碼如下:

public static void main(String[] args) throws IOException {//一個讀通道,一個寫通道ReadableByteChannel source = Channels.newChannel(System.in);WritableByteChannel dest = Channels.newChannel(System.out);channelCopy(source,dest);source.close();dest.close();}private static void channelCopy(ReadableByteChannel source, WritableByteChannel dest) throws IOException{ByteBuffer byteBuffer = ByteBuffer.allocate(16 * 1024);ByteBuffer flag = ByteBuffer.allocate(4);while (source.read(byteBuffer) != -1) {byteBuffer.flip();//輸出標記flag.put((byte)'-').put((byte)'-').put((byte)'-').put((byte) '>');flag.flip();dest.write(flag);dest.write(byteBuffer);flag.clear();byteBuffer.compact();}byteBuffer.flip();//確保緩沖區排干凈while (byteBuffer.hasRemaining()) {flag.putChar('-').putChar('-').putChar('-');flag.flip();dest.write(byteBuffer);flag.clear();}}

測試輸入輸出如下:

通道關閉

與緩沖區不同,通道不能重復利用,打開通道即代表與一個特定的IO服務的特定鏈接并封裝該鏈接的狀態,通道關閉時,連接丟失,通道不在連接任何東西。
調用close方法時,可能導致線程暫時阻塞,關閉的通道上調用close方法不會產生任何操作,只會立即返回。可以通過isOpen方法判斷通道狀態。
如果一個線程被中斷,那么這個線程訪問的通道將立即關閉,這也是為程序健壯性而采用的一種權衡。

Scatter/Gather

在多個緩沖區實現一個簡單的IO操作:
對于write,數據是從幾個緩沖區按順序抽取(gather)并沿著通道發送。該gather過程,好比全部緩沖區內容被連接起來,并在發送前存放到一個大的緩沖區。
對于read,從通道讀取的數據會被按順序散布(scatter)到多個緩沖區,將每個緩沖區填滿直至通道中的數據或緩沖區的空間被消耗完。
接口定義如下, 其中read和write入參時Buffer數組:

public interface ScatteringByteChannelextends ReadableByteChannel {public long read (ByteBuffer [] dsts)throws IOException;public long read (ByteBuffer [] dsts, int offset, int length)throws IOException; } public interface GatheringByteChannelextends WritableByteChannel {public long write(ByteBuffer[] srcs)throws IOException;public long write(ByteBuffer[] srcs, int offset, int length)throws IOException; }

文件通道

具體來講FileChannel,接口如下:

public abstract class FileChannelextends AbstractInterruptibleChannelimplements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel

FileChannel 對象是線程安全(thread-safe)的.
對于文件IO,最強大之處在于異步IO,它允許一個進程可以從操作系統請求一個或多個IO操作而不必等待這些操作完成。

文件通道代碼示例

  • 將緩沖區數據,通過文件channel寫入文件
public static void write(String filePath) throws Exception {/*寫文件,使用FileOutputStream,RandomAccessFile都可以。*/ /* RandomAccessFile file = new RandomAccessFile(filePath,"rw");*/FileOutputStream file = new FileOutputStream(new File(filePath));ByteBuffer byteBuffer = ByteBuffer.allocate(500);String str = "hello LK";/*數據寫入緩沖區*/byteBuffer.put(str.getBytes());byteBuffer.flip();FileChannel fileChannel = file.getChannel();//將緩沖區數據寫入文件通道fileChannel.write(byteBuffer);byteBuffer.clear();fileChannel.close();}
  • 通過文件channel,將文件中的數據讀入緩沖區
public static void read(String filePath) throws Exception {FileInputStream fileInputStream = new FileInputStream(new File(filePath));/*一個FileChannel對象卻只能通過在一個打開的RandomAccessFile、FileInputStream或FileOutputStream對象上調用getChannel()方法來獲取,開發者不能直接創建一個FileChannel*/FileChannel fileChannel = fileInputStream.getChannel();ByteBuffer byteBuffer = ByteBuffer.allocate(500);//將文件channel讀入緩沖區fileChannel.read(byteBuffer);byteBuffer.flip();while (byteBuffer.hasRemaining()){System.out.print((char)byteBuffer.get());}byteBuffer.clear();fileChannel.close();}

Socket通道

新的Socket通道類可以運行非阻塞模式,并且是可選擇的。借助新的NIO類,一個或幾個線程可以管理成百上千的活動socket連接,并且只有很少的性能順勢。
全部 socket 通道類(DatagramChannel、SocketChannel 和 ServerSocketChannel)都是由位于java.nio.channels.spi 包中的AbstractSelectableChannel引申而來。
DatagramChannel 和 SocketChannel 實現定義讀和寫功能的接口而 ServerSocketChannel 不實現。ServerSocketChannel 負責監聽傳入的連接和創建新的SocketChannel 對象,它本身從不傳 輸數據。

Socket通道代碼示例

啟動一個ServerSocketChannel,監聽8001端口,非阻塞模式。啟動10個SocketChannel線程向ServerSocketChannel寫數據。
ServerSocketChannel代碼如下:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();/*非阻塞*/serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(new InetSocketAddress(port));System.out.println("ServerSocketChannel is OK,waiting @[" + LocalDateTime.now() + "]");for (; ; ) {SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel == null) {Thread.sleep(1000);System.out.println("ServerSocketChannel sleep 1000ms.");continue;}String connectIP = socketChannel.socket().getRemoteSocketAddress().toString();System.out.println("客戶端已有數據到來,客戶端ip為:" + connectIP + ", 時間為" + LocalDateTime.now());ByteBuffer byteBuffer = ByteBuffer.allocate(1024);socketChannel.read(byteBuffer);byteBuffer.flip();while (byteBuffer.hasRemaining()) {System.out.print((char) byteBuffer.get());}socketChannel.close();}}

啟動10個SocketCHannel代碼如下:

private static final int port = 8001;public static void main(String[] args) {for (int i=0;i<10;i++) {new SocketChannelImpl(port,i).start();}}private static class SocketChannelImpl extends Thread {private int count = 0;private int port;public SocketChannelImpl(int port,int count){this.port = port;this.count = count;}@Overridepublic void run() {try {SocketChannel socketChannel = SocketChannel.open();/*非阻塞*/socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress(port));for (;!socketChannel.finishConnect();) {System.out.println("connectting....");Thread.sleep(50);}ByteBuffer byteBuffer = ByteBuffer.allocate(1024);String content = "hello, i am client--------->" + count;byteBuffer.put(content.getBytes());byteBuffer.flip();socketChannel.write(byteBuffer);byteBuffer.clear();socketChannel.close();} catch (Exception e) {e.printStackTrace();}}}

運行結果如下:

補充下:
ServerSocketChannel監聽的是8001端口,你可以在瀏覽器,輸入:http://localhost:8001/helloworld,你會發現你的ServerSocketChannel也是可以收到數據了,這也web服務器處理的基礎了。

總結

以上,了解了基本的通道操作,文件通道和socket通道的使用示例,我覺得點個贊,不過分=。=
以上所有代碼示例,可以fork這里:github

謝謝

轉載于:https://www.cnblogs.com/lknny/p/9096212.html

總結

以上是生活随笔為你收集整理的Java NIO之通道的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。