Java NIO(三):FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel

FileChannel

  • 打開 FileChannel,需要通過 InputStream、OutputStream 或 RandomAccessFile 來獲取一個 FileChannel 實(shí)例
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
  • 從 FileChannel 讀取數(shù)據(jù),需要分配一個 Buffer,在將 FileChannel 中的數(shù)據(jù)讀到 Buffer 中
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
  • 向 FileChannel 寫數(shù)據(jù)
String str = "abc";
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
byteBuffer.put(str.getBytes());
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
    fileChannel.write(byteBuffer);
}
  • 用完 FileChannel 后必須將其關(guān)閉
channel.close();
  • 若需要在特定位置進(jìn)行數(shù)據(jù)讀/寫操作可以調(diào)用 position() 方法獲取 FileChannel 當(dāng)前位置,也可以設(shè)置當(dāng)前位置(注意:如果將位置設(shè)置在文件結(jié)束符之后,然后在向通道寫數(shù)據(jù),文件將撐大到當(dāng)前位置并寫入數(shù)據(jù),這可能導(dǎo)致"文件空洞"
long pos = channel.position();
channel.position(pos +123);
  • 調(diào)用 size() 方法返回文件的大小
long fileSize = channel.size();
  • 使用 truncate() 方法截取一個文件,截取文件時文件中指定長度后面的部分將被刪除
channel.truncate(1024);
  • force() 方法將通道里尚未寫入磁盤的數(shù)據(jù)強(qiáng)制寫到磁盤上,出于性能方面考慮,操作系統(tǒng)將數(shù)據(jù)緩存在內(nèi)存中,無法保證寫入到 FileChannel 里的數(shù)據(jù)一定會即時寫到磁盤上,force() 方法有一個 boolean 類型的參數(shù),指明是否同時將文件元數(shù)據(jù)(權(quán)限信息等)寫到磁盤上
channel.force(true);

通道間的數(shù)據(jù)傳輸

  • FileChannel 的 transferFrom() 方法可以將數(shù)據(jù)從源通道傳輸?shù)?FileChannel 中
try (RandomAccessFile raf = new RandomAccessFile("/Users/linyuan/Documents/字目錄.txt", "rw");
    RandomAccessFile toFile = new RandomAccessFile("/Users/linyuan/Documents/toFile.txt", "rw")) {
    FileChannel fromChannel = raf.getChannel();
    FileChannel toChannel = toFile.getChannel();
    long position = 0;
    long count = fromChannel.size();
    // position 表示從 position 處開始向目標(biāo)文件寫入數(shù)據(jù),count 表示最多傳輸?shù)淖止?jié)數(shù)
    // 如果源通道的剩余空間小于 count 個字節(jié),則所傳輸?shù)淖止?jié)數(shù)要小于請求的字節(jié)數(shù)
    toChannel.transferFrom(fromChannel, position, count);
} catch (Exception e) {
    e.printStackTrace();
}
  • transferTo() 方法將數(shù)據(jù)從 FileChannel 傳輸?shù)狡渌?channel 中

SocketChannel

  • SocketChannel 是一個連接到 TCP 網(wǎng)絡(luò)套接字的通道
  • 通過 SocketChannel 的 open() 創(chuàng)建 SocketChannel 實(shí)例,并通過 connect() 連接服務(wù)器
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 80));

非阻塞模式

  • 此時調(diào)用 connect 方法可能在建立連接前就返回了,為了確定是否建立連接,可以調(diào)用 finishConnect 方法
socketChannel.configureBlocking(false);     // 設(shè)置為非阻塞模式
socketChannel.connect(new InetSocketAddress("http://www.baidu.com", 80));
while(!socketChannel.finishConnect() ){
    //wait, or do something else...
}

ServerSocketChannel

  • ServerSocketChannel 是一個服務(wù)器端 SocketChannel,監(jiān)聽 TCP 連接通道
  • 通過 ServerSocketChannel 的 open() 創(chuàng)建 ServerSocketChannel 實(shí)例,并綁定端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
  • 循環(huán)調(diào)用 accept() 等待客戶端連接,該方法默認(rèn)為阻塞狀態(tài)
while(true){
    SocketChannel socketChannel =serverSocketChannel.accept();
    //do something with socketChannel...
}

非阻塞模式

  • 在非阻塞模式下 accept 方法會立即返回,如果沒有新客戶端連接,則返回值為 null,需要檢查 SocketChannel 是否為 null
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);   // 設(shè)置為非阻塞模式
while(true){
    SocketChannel socketChannel = serverSocketChannel.accept();
    if(socketChannel != null){
    //do something with socketChannel...
    }
}

DatagramChannel

  • DatagramChannel 是一個能收發(fā) UDP 數(shù)據(jù)包的通道,因為 UDP 是無連接的網(wǎng)絡(luò),所以不能像其它通道一樣讀取和寫入,只能發(fā)送和接收數(shù)據(jù)包
  • 通過 DatagramChannel 的open() 創(chuàng)建 DatagramChannel 實(shí)例,并綁定端口
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
  • 通過 receive() 接收數(shù)據(jù)報
ByteBuffer buf = ByteBuffer.allocate(48);
channel.receive(buf);
  • 通過 send() 發(fā)送數(shù)據(jù)報
String str = "新的一天";
ByteBuffer buf = ByteBuffer.allocate(48);
buf.put(str.getBytes());
buf.flip();
channel.send(buf, new InetSocketAddress("localhost", 9999));

連接到特定的地址

  • DatagramChannel 可以“連接”到網(wǎng)絡(luò)中特定地址,通過 connect 方法,但這種連接并非真正的連接,而是鎖住發(fā)送的地址,讓其只能從特定地址收發(fā)數(shù)據(jù)
channel.connect(new InetSocketAddress("localhost", 80));
  • 當(dāng)連接后可以使用 read 和 write 方法
int bytesRead = channel.read(buf);
int bytesWritten = channel.write(but);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Java NIO(New IO)是從Java 1.4版本開始引入的一個新的IO API,可以替代標(biāo)準(zhǔn)的Java I...
    JackChen1024閱讀 7,956評論 1 143
  • (轉(zhuǎn)載說明:本文非原創(chuàng),轉(zhuǎn)載自http://ifeve.com/java-nio-all/) Java NIO: ...
    柳岸閱讀 891評論 0 3
  • (轉(zhuǎn)載說明:本文非原創(chuàng),轉(zhuǎn)載自http://ifeve.com/java-nio-all/) Java NIO: ...
    數(shù)獨(dú)題閱讀 869評論 0 3
  • 前言: 之前的文章《Java文件IO常用歸納》主要寫了Java 標(biāo)準(zhǔn)IO要注意的細(xì)節(jié)和技巧,由于網(wǎng)上各種學(xué)習(xí)途徑,...
    androidjp閱讀 3,244評論 0 22
  • NIO 并發(fā)編程網(wǎng) - ifeve.comJava NIO系列教程 筆記 http://ifeve.com...
    梓青閱讀 628評論 0 0

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