1. 程式人生 > >Java NIO 通道的實現型別

Java NIO 通道的實現型別

檔案通道

Java NIO中的FileChannel是一個連線到檔案的通道。可以通過檔案通道讀寫檔案。 

FileChannel無法設定為非阻塞模式,它總是執行在阻塞模式下。 

開啟FileChannel 

在使用FileChannel之前,必須先開啟它。但是,我們無法直接開啟一個FileChannel,需要通過使用一個InputStream、OutputStream或RandomAccessFile來獲取一個FileChannel例項。下面是通過RandomAccessFile開啟FileChannel的示例: 

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");  
FileChannel inChannel = aFile.getChannel(); 

從FileChannel讀取資料 

呼叫多個read()方法之一從FileChannel中讀取資料。如: 

ByteBuffer buf = ByteBuffer.allocate(48);  
int bytesRead = inChannel.read(buf);  
首先,分配一個Buffer。從FileChannel中讀取的資料將被讀到Buffer中。 

然後,呼叫FileChannel.read()方法。該方法將資料從FileChannel讀取到Buffer中。read()方法返回的int值表示了有多少位元組被讀到了Buffer中。如果返回-1,表示到了檔案末尾。  

向FileChannel寫資料 


使用FileChannel.write()方法向FileChannel寫資料,該方法的引數是一個Buffer。如: 

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    channel.write(buf);  
}  

注意FileChannel.write()是在while迴圈中呼叫的。因為無法保證write()方法一次能向FileChannel寫入多少位元組,因此需要重複呼叫write()方法,直到Buffer中已經沒有尚未寫入通道的位元組。

關閉FileChannel
用完FileChannel後必須將其關閉。如: 

channel.close();  
FileChannel的position方法 
有時可能需要在FileChannel的某個特定位置進行資料的讀/寫操作。可以通過呼叫position()方法獲取FileChannel的當前位置。 
也可以通過呼叫position(long pos)方法設定FileChannel的當前位置。 

這裡有兩個例子:

long pos = channel.position();  
channel.position(pos +123);  
如果將位置設定在檔案結束符之後,然後試圖從檔案通道中讀取資料,讀方法將返回-1 —— 檔案結束標誌。 
如果將位置設定在檔案結束符之後,然後向通道中寫資料,檔案將撐大到當前位置並寫入資料。這可能導致“檔案空洞”,磁碟上物理檔案中寫入的資料間有空隙。

 FileChannel的size方法 

FileChannel例項的size()方法將返回該例項所關聯檔案的大小。如: 

long fileSize = channel.size();  
FileChannel的truncate方法 

可以使用FileChannel.truncate()方法擷取一個檔案。擷取檔案時,檔案將中指定長度後面的部分將被刪除。如:  

channel.truncate(1024);  
這個例子擷取檔案的前1024個位元組。 
FileChannel的force方法 
FileChannel.force()方法將通道里尚未寫入磁碟的資料強制寫到磁碟上。出於效能方面的考慮,作業系統會將資料快取在記憶體中,所以無法保證寫入到FileChannel裡的資料一定會即時寫到磁碟上。要保證這一點,需要呼叫force()方法。 
force()方法有一個boolean型別的引數,指明是否同時將檔案元資料(許可權資訊等)寫到磁碟上。 
下面的例子同時將檔案資料和元資料強制寫到磁碟上: 
channel.force(true);  

Socket 通道

Java NIO中的SocketChannel是一個連線到TCP網路套接字的通道。可以通過以下2種方式建立SocketChannel: 

  • 開啟一個SocketChannel並連線到網際網路上的某臺伺服器。
  • 一個新連線到達ServerSocketChannel時,會建立一個SocketChannel。

開啟 SocketChannel 

SocketChannel socketChannel = SocketChannel.open();  
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));  

關閉 SocketChannel 

socketChannel.close();  
從 SocketChannel 讀取資料 
ByteBuffer buf = ByteBuffer.allocate(48);  
int bytesRead = socketChannel.read(buf);  
首先,分配一個Buffer。從SocketChannel讀取到的資料將會放到這個Buffer中。 

然後,呼叫SocketChannel.read()。該方法將資料從SocketChannel 讀到Buffer中。read()方法返回的int值表示讀了多少位元組進Buffer裡。如果返回的是-1,表示已經讀到了流的末尾(連線關閉了)。 

寫入 SocketChannel 

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    channel.write(buf);  
}  

注意SocketChannel.write()方法的呼叫是在一個while迴圈中的。Write()方法無法保證能寫多少位元組到SocketChannel。所以,我們重複呼叫write()直到Buffer沒有要寫的位元組為止。

非阻塞模式 

可以設定 SocketChannel 為非阻塞模式(non-blocking mode).設定之後,就可以在非同步模式下呼叫connect(), read() 和write()了。

connect() 
如果SocketChannel在非阻塞模式下,此時呼叫connect(),該方法可能在連線建立之前就返回了。為了確定連線是否建立,可以呼叫finishConnect()的方法。像這樣:

ocketChannel.configureBlocking(false);  
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));  
  
while(! socketChannel.finishConnect() ){  
    //wait, or do something else...  
} 

write() 

非阻塞模式下,write()方法在尚未寫出任何內容時可能就返回了。所以需要在迴圈中呼叫write()。前面已經有例子了,這裡就不贅述了。 

read() 

非阻塞模式下,read()方法在尚未讀取到任何資料時可能就返回了。所以需要關注它的int返回值,它會告訴你讀取了多少位元組。 

非阻塞模式與選擇器 

非阻塞模式與選擇器搭配會工作的更好,通過將一或多個SocketChannel註冊到Selector,可以詢問選擇器哪個通道已經準備好了讀取,寫入等。Selector與SocketChannel的搭配使用會在後面詳講。

ServerSocket 通道 

Java NIO中的 ServerSocketChannel 是一個可以監聽新進來的TCP連線的通道,就像標準IO中的ServerSocket一樣。ServerSocketChannel類在 java.nio.channels包中。

//通過呼叫 ServerSocketChannel.open() 方法來開啟ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); //do something with socketChannel... } //通過呼叫ServerSocketChannel.close() 方法來關閉ServerSocketChannel.serverSocketChannel.close(); 

監聽新進來的連線 

通過 ServerSocketChannel.accept() 方法監聽新進來的連線。當 accept()方法返回的時候,它返回一個包含新進來的連線的 SocketChannel。因此,accept()方法會一直阻塞到有新連線到達。 通常不會僅僅只監聽一個連線,在while迴圈中呼叫 accept()方法. 如下面的例子: 

while(true){  
    SocketChannel socketChannel = serverSocketChannel.accept();  
  
    //do something with socketChannel...  
}  

當然,也可以在while迴圈中使用除了true以外的其它退出準則。 

非阻塞模式 
ServerSocketChannel可以設定成非阻塞模式。在非阻塞模式下,accept() 方法會立刻返回,如果還沒有新進來的連線,返回的將是null。 因此,需要檢查返回的SocketChannel是否是null。如:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
  
serverSocketChannel.socket().bind(new InetSocketAddress(9999));  
serverSocketChannel.configureBlocking(false);  
  
while(true){  
    SocketChannel socketChannel = serverSocketChannel.accept();  
  
    if(socketChannel != null){  
        //do something with socketChannel...  
    }  
}  

Datagram 通道 

Java NIO中的DatagramChannel是一個能收發UDP包的通道。因為UDP是無連線的網路協議,所以不能像其它通道那樣讀取和寫入。它傳送和接收的是資料包。 

開啟 DatagramChannel 

DatagramChannel channel = DatagramChannel.open();  
channel.socket().bind(new InetSocketAddress(9999));  
這個例子開啟的 DatagramChannel可以在UDP埠9999上接收資料包。 

接收資料 

ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
channel.receive(buf);  

receive()方法會將接收到的資料包內容複製到指定的Buffer. 如果Buffer容不下收到的資料,多出的資料將被丟棄。

傳送資料

String newData = "New String to write to file..." + System.currentTimeMillis();  
  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
buf.flip();  
  
int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80)); 
這個例子傳送一串字元到”jenkov.com”伺服器的UDP埠80。 因為服務端並沒有監控這個埠,所以什麼也不會發生。也不會通知你發出的資料包是否已收到,因為UDP在資料傳送方面沒有任何保證。  

連線到特定的地址

可以將DatagramChannel“連線”到網路中的特定地址的。由於UDP是無連線的,連線到特定地址並不會像TCP通道那樣建立一個真正的連線。而是鎖住DatagramChannel ,讓其只能從特定地址收發資料。

channel.connect(new InetSocketAddress("jenkov.com", 80));  
當連線後,也可以使用read()和write()方法,就像在用傳統的通道一樣。只是在資料傳送方面沒有任何保證。這裡有幾個例子:  
int bytesRead = channel.read(buf);  
int bytesWritten = channel.write(but);  

管道(Pipe)

Java NIO 管道是2個執行緒之間的單向資料連線。Pipe有一個source通道和一個sink通道。資料會被寫到sink通道,從source通道讀取。 


建立管道

Pipe pipe = Pipe.open();  
向管道寫資料

要向管道寫資料,需要訪問sink通道。像這樣:   

Pipe.SinkChannel sinkChannel = pipe.sink();  

通過呼叫SinkChannel的write()方法,將資料寫入SinkChannel,像這樣: 

String newData = "New String to write to file..." + System.currentTimeMillis();  
ByteBuffer buf = ByteBuffer.allocate(48);  
buf.clear();  
buf.put(newData.getBytes());  
  
buf.flip();  
  
while(buf.hasRemaining()) {  
    sinkChannel.write(buf);
}  
從管道讀取資料 

從讀取管道的資料,需要訪問source通道,像這樣: 

Pipe.SourceChannel sourceChannel = pipe.source();  

呼叫source通道的read()方法來讀取資料,像這樣: 

ByteBuffer buf = ByteBuffer.allocate(48);  
  
int bytesRead = inChannel.read(buf);  
read()方法返回的int值會告訴我們多少位元組被讀進了緩衝區。 

相關推薦

Java NIO 通道實現型別

檔案通道Java NIO中的FileChannel是一個連線到檔案的通道。可以通過檔案通道讀寫檔案。 FileChannel無法設定為非阻塞模式,它總是執行在阻塞模式下。 開啟FileChannel 在使用FileChannel之前,必須先開啟它。但是,我們無法直接開啟一個F

java nio實現原理

阻塞 3.3 keys div nbsp select 行數 多路復用 class 1 什麽是java nio java nio就是java非阻塞io。 2 什麽是channel channel是到打開的文件的連接,只要是支持讀寫操作的實體都可以稱為文件,文件可以是硬件設備

Java NIO 通道(Channel) 學習筆記

 一、通道(Channel):用於源節點與目標節點的連線。在 Java NIO 中負責緩衝區中資料的傳輸。Channel 本身不儲存資料,因此需要配合緩衝區進行傳輸。    二、通道的主要實現類      java.nio.c

Java NIO 通道

一、通道(Channel):用於源節點與目標節點的連線。在 Java NIO 中負責緩衝區中資料的傳輸。Channel 本身不儲存資料,因此需要配合緩衝區進行傳輸。     二、通道的主要實現類    java.nio.channels.Cha

Java NIO通道(Channel)

NIO 中主要的三個概念為緩衝區、通道、選擇器,它們之間的關係如下所示: 此處要提醒的是,JDK 1.7 升級了 NIO 類庫,升級後的 NIO 類庫被稱為 NIO2.0。在 NIO2.0 中,提供了非同步檔案I/O操作,同時提供了與 UNIX 網路程式設計事

Java NIO 通道(二)通道基礎

概念通道是NIO提供的一個全新的東西,提供與I/O服務的直接連線。Channel用於在位元組緩衝區和位於通道的另一側的實體(通常是一個檔案或者套接字)之間進行有效的傳輸資料。介面定義 public interface Channel extends Closea

java nio--采用Selector實現Socket通信

lock finish taf 取數 block static isempty inpu col server: 1 /** 2 * 選擇器服務端 3 * Created by ascend on 2017/6/9 9:30. 4 */ 5 pu

java nio之 channel通道(二)

java niojava nio 通道上一篇文章裏就講述過,channel總是寫數據的時候,要先把數據寫入到bytebuffer,讀數據的時候總是要先從channel中讀入到bytebuffer。如下圖,這個圖是好多知名博客常用的圖,很好理解這個channel。channel分為一下幾種:FileChanne

Java NIO 利用通道完成文件復制(MappedByteBuffer)

http out println code unit pmo buffer log put 相關學習網址: import java.io.IOException;import java.nio.MappedByteBuffer;import java.nio.channel

Java NIO 實現文件復制

print utc code generate pri 循環 while clear generated /* *int bytesRead=inChannel.read(buf); * 這句話是從文件流中讀取一個buf內容,返回讀取的大小, * 如果是讀取到文件尾部的

nio通道通信實現的文件復制

exce cat org junit from chan ava pac nts 1 package edzy.nio; 2 3 import org.junit.Test; 4 5 import java.io.FileInputStream; 6 im

Java NIO教程(五) 通道之間的資料傳輸

                                 Java NIO教程(五) 通道之間的資料傳輸

Java NIO通道Channel分析

目錄 簡介 檔案通道FileChannel Socket通道 其他內容                              &n

proxyme——java NIO實現的http代理,支援https

proxyme 一個http代理 使用java NIO的http代理。支援https。建議不要再chrome上使用本代理,因為chrome本身會請求很多谷歌的api,結果被牆住了,又只有兩個執行緒,導致其他都被阻塞,很尷尬。 之前也打算做過這個東西,結果做出來的有點缺陷(現在想可能是

Java NIO 學習筆記(二)----聚集和分散,通道通道

目錄: Java NIO 學習筆記(一)----概述,Channel/Buffer Java NIO 學習筆記(二)----聚集和分散,通道到通道 Scatter / Gather 通道的聚集和分散操作 NIO 具有內建的 scatter/gather 支援,用於描述讀取和寫入通道的操作。 分散(

Java NIO 學習筆記(四)----檔案通道和網路通道

目錄: Java NIO 學習筆記(一)----概述,Channel/Buffer Java NIO 學習筆記(二)----聚集和分散,通道到通道 Java NIO 學習筆記(三)----Selector Java NIO 學習筆記(四)----檔案通道和網路通道 FileChannel 檔案通道 Fil

Java NIO 學習筆記(六)----非同步檔案通道 AsynchronousFileChannel

目錄: Java NIO 學習筆記(一)----概述,Channel/Buffer Java NIO 學習筆記(二)----聚集和分散,通道到通道 Java NIO 學習筆記(三)----Selector Java NIO 學習筆記(四)----檔案通道和網路通道 Java NIO 學習筆記(五)----路徑

Java提供了哪些IO方式?NIO如何實現複用?

一、Java提供了哪些IO方式? Java IO方式由很多種,基於不同的IO抽象模型和互動方式,可以進行簡單區分。 首先,傳統的Java.IO包,它基於流模型實現,提供了我們最熟知的一些IO功能,比如File抽象、輸入輸出流等。互動方式是同步、阻塞的方式。也就是

java nio系列教程(2)---channel(通道介紹)和使用

大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油 ​   package com.zzh.buffer; import com.google.common.collect.Lists; import org.junit.jupiter.api.Test; imp

Java NIO(二)通道Channel

一、通道(Channel): 用於源節點與目標節點的連線。在 Java NIO 中負責緩衝區中資料的傳輸。Channel 本身不儲存資料,因此需要配合緩衝區進行傳輸。  二、通道的主要實現類      java.nio.channels.C