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