Carson帶你學(xué)Java:帶你全面了解神秘的Java NIO


前言

  • JDK 1.4后,Java提供了一個(gè)全新的IO API,即 Java New IO
  • 本文 全面 & 詳細(xì)解析Java New IO,希望你們會(huì)喜歡

目錄

示意圖

儲(chǔ)備知識(shí):Java IO

示意圖

1. 定義

  • Java New IO
  • 是1個(gè)全新的、 JDK 1.4后提供的 IO API

2. 作用

  • 提供了與標(biāo)準(zhǔn)IO不同的IO工作方式
  • 可替代 標(biāo)準(zhǔn)Java IOIO API

3. 新特性

對(duì)比于 Java IO,NIO具備的新特性如下

示意圖

4. 核心組件

Java NIO的核心組件 包括:

  • 通道(Channel
  • 緩沖區(qū)(Buffer
  • 選擇器(Selectors

下面將詳細(xì)介紹:

示意圖

5. 具體使用

5.1 基于通道 & 緩沖數(shù)據(jù)

具體步驟如下:

    // 1. 獲取數(shù)據(jù)源 和 目標(biāo)傳輸?shù)氐妮斎胼敵隽鳎ù颂幰詳?shù)據(jù)源 = 文件為例)
    FileInputStream fin = new FileInputStream(infile);
    FileOutputStream fout = new FileOutputStream(outfile);

    // 2. 獲取數(shù)據(jù)源的輸入輸出通道
    FileChannel fcin = fin.getChannel();
    FileChannel fcout = fout.getChannel();

    // 3. 創(chuàng)建 緩沖區(qū) 對(duì)象:Buffer(共有2種方法)
     // 方法1:使用allocate()靜態(tài)方法
     ByteBuffer buff = ByteBuffer.allocate(256);
     // 上述方法創(chuàng)建1個(gè)容量為256字節(jié)的ByteBuffer
     // 注:若發(fā)現(xiàn)創(chuàng)建的緩沖區(qū)容量太小,則重新創(chuàng)建一個(gè)大小合適的緩沖區(qū)

    // 方法2:通過(guò)包裝一個(gè)已有的數(shù)組來(lái)創(chuàng)建
     // 注:通過(guò)包裝的方法創(chuàng)建的緩沖區(qū)保留了被包裝數(shù)組內(nèi)保存的數(shù)據(jù)
     ByteBuffer buff = ByteBuffer.wrap(byteArray);

     // 額外:若需將1個(gè)字符串存入ByteBuffer,則如下
     String sendString="你好,服務(wù)器. ";
     ByteBuffer sendBuff = ByteBuffer.wrap(sendString.getBytes("UTF-16"));

    // 4. 從通道讀取數(shù)據(jù) & 寫(xiě)入到緩沖區(qū)
    // 注:若 以讀取到該通道數(shù)據(jù)的末尾,則返回-1
    fcin.read(buff);

    // 5. 傳出數(shù)據(jù)準(zhǔn)備:將緩存區(qū)的寫(xiě)模式 轉(zhuǎn)換->> 讀模式
    buff.flip();

    // 6. 從 Buffer 中讀取數(shù)據(jù) & 傳出數(shù)據(jù)到通道
    fcout.write(buff);

    // 7. 重置緩沖區(qū)
    // 目的:重用現(xiàn)在的緩沖區(qū),即 不必為了每次讀寫(xiě)都創(chuàng)建新的緩沖區(qū),在再次讀取之前要重置緩沖區(qū)
    // 注:不會(huì)改變緩沖區(qū)的數(shù)據(jù),只是重置緩沖區(qū)的主要索引值
    buff.clear();

5.2 基于選擇器(Selecter)

具體步驟如下:

// 1. 創(chuàng)建Selector對(duì)象   
Selector sel = Selector.open();

// 2. 向Selector對(duì)象綁定通道   
 // a. 創(chuàng)建可選擇通道,并配置為非阻塞模式   
 ServerSocketChannel server = ServerSocketChannel.open();   
 server.configureBlocking(false);   
 
 // b. 綁定通道到指定端口   
 ServerSocket socket = server.socket();   
 InetSocketAddress address = new InetSocketAddress(port);   
 socket.bind(address);   
 
 // c. 向Selector中注冊(cè)感興趣的事件   
 server.register(sel, SelectionKey.OP_ACCEPT);    
 return sel;

// 3. 處理事件
try {    
    while(true) { 
        // 該調(diào)用會(huì)阻塞,直到至少有一個(gè)事件就緒、準(zhǔn)備發(fā)生 
        selector.select(); 
        // 一旦上述方法返回,線程就可以處理這些事件
        Set<SelectionKey> keys = selector.selectedKeys(); 
        Iterator<SelectionKey> iter = keys.iterator(); 
        while (iter.hasNext()) { 
            SelectionKey key = (SelectionKey) iter.next(); 
            iter.remove(); 
            process(key); 
        }    
    }    
} catch (IOException e) {    
    e.printStackTrace();   
}

6. 實(shí)例講解

  • 實(shí)例說(shuō)明:實(shí)現(xiàn)文件復(fù)制功能
  • 實(shí)現(xiàn)方式:通道FileChannel、 緩沖區(qū)ByteBuffer
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Test {

    public static void main(String[] args) throws IOException {
        // 設(shè)置輸入源 & 輸出地 = 文件
        String infile = "C:\\copy.sql";
        String outfile = "C:\\copy.txt";

        // 1. 獲取數(shù)據(jù)源 和 目標(biāo)傳輸?shù)氐妮斎胼敵隽鳎ù颂幰詳?shù)據(jù)源 = 文件為例)
        FileInputStream fin = new FileInputStream(infile);
        FileOutputStream fout = new FileOutputStream(outfile);

        // 2. 獲取數(shù)據(jù)源的輸入輸出通道
        FileChannel fcin = fin.getChannel();
        FileChannel fcout = fout.getChannel();

        // 3. 創(chuàng)建緩沖區(qū)對(duì)象
        ByteBuffer buff = ByteBuffer.allocate(1024);
        
        while (true) {

            // 4. 從通道讀取數(shù)據(jù) & 寫(xiě)入到緩沖區(qū)
            // 注:若 以讀取到該通道數(shù)據(jù)的末尾,則返回-1  
            int r = fcin.read(buff);
            if (r == -1) {
                break;
            }
            // 5. 傳出數(shù)據(jù)準(zhǔn)備:調(diào)用flip()方法  
            buff.flip();
            
            // 6. 從 Buffer 中讀取數(shù)據(jù) & 傳出數(shù)據(jù)到通道
            fcout.write(buff);
            
            // 7. 重置緩沖區(qū)
            buff.clear();
            
          }
        }

}

7. 與Java IO的區(qū)別

示意圖

8. 總結(jié)

本文全面講解了Java中的NIO的相關(guān)知識(shí)。


歡迎關(guān)注Carson_Ho的簡(jiǎn)書(shū)!

分享Android技術(shù)干貨,追求短、平、快,但卻不缺深度。


請(qǐng)點(diǎn)贊!因?yàn)槟愕墓膭?lì)是我寫(xiě)作的最大動(dòng)力!

相關(guān)文章閱讀
Android開(kāi)發(fā):最全面、最易懂的Android屏幕適配解決方案
Android事件分發(fā)機(jī)制詳解:史上最全面、最易懂
Android開(kāi)發(fā):史上最全的Android消息推送解決方案
Android開(kāi)發(fā):最全面、最易懂的Webview詳解
Android開(kāi)發(fā):JSON簡(jiǎn)介及最全面解析方法!
Android四大組件:Service服務(wù)史上最全面解析
Android四大組件:BroadcastReceiver史上最全面解析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容