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);