Java NIO(New IO)
是一個(gè)可以替代標(biāo)準(zhǔn)Java IO API的IO API(從Java 1.4開(kāi)始),Java NIO提供了與標(biāo)準(zhǔn)IO不同的IO工作方式。
它有三個(gè)核心分別是:Channel、Buffer和Selector
Channel
Channel翻譯過(guò)來(lái)是“通道、頻道”,其實(shí)可以用流的概念簡(jiǎn)單的去概括他,數(shù)據(jù)可以從Channel讀到Buffer中,也可以從Buffer 寫(xiě)到Channel中。其實(shí)理解起來(lái)很簡(jiǎn)單:Buffer是緩存嘛,緩存的東西我們當(dāng)然要可以取出來(lái)了,向誰(shuí)取呢?Channel唄;我們當(dāng)然也要向緩存里存東西啊,誰(shuí)去向緩存里填充東西?Channel唄;Easy~~
Buffer
Buffer就是“緩存”的意思嘛,沒(méi)啥好說(shuō)的,它覆蓋了可以用IO發(fā)送的基本數(shù)據(jù)類(lèi)型。
Selector
Selector厲害了!翻譯來(lái)是“選擇器”。
我們平時(shí)的BIO是:即客戶(hù)端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理,如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開(kāi)銷(xiāo)。但是現(xiàn)在是NIO了,NIO提供了Selector,服務(wù)器實(shí)現(xiàn)模式從一個(gè)連接對(duì)應(yīng)一個(gè)線程轉(zhuǎn)化為了一個(gè)請(qǐng)求對(duì)應(yīng)。一個(gè)線程,即客戶(hù)端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上,多路復(fù)用器輪詢(xún)到連接有I/O請(qǐng)求時(shí)才啟動(dòng)一個(gè)線程進(jìn)行處理。
說(shuō)起來(lái)很復(fù)雜,其實(shí)不然:
比如說(shuō),我想使用多個(gè)Channel,但是我不必開(kāi)啟多個(gè)線程去管理,我在這里就可以利用Selector去進(jìn)行管理這些Channel。
Channel的使用
這里記一下Channel:
NIO的Channel類(lèi)似流,但是不能完全當(dāng)做流:
1.流的讀寫(xiě)是單向的,但是Channel是可以通過(guò)一個(gè)Channel讀和寫(xiě)的,是雙向的。
2.Channel是可以異步讀寫(xiě)的。
3.Channel的使用是需要Buffer配合的。
簡(jiǎn)單的寫(xiě)一下Channel的小栗子:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
buf.flip();
while(buf.hasRemaining()){
System.out.print((char) buf.get());
}
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
上面的程序是在并發(fā)編程網(wǎng)照著敲下來(lái)的,而且沒(méi)加注釋?zhuān)覀儠?huì)發(fā)現(xiàn)出現(xiàn)了喜聞樂(lè)見(jiàn)的中文亂碼問(wèn)題ㄟ( ▔, ▔ )ㄏ
~只能通過(guò)自己嘗試去解決啦!
經(jīng)過(guò)查找資料寫(xiě)了如下的代碼,并且加了注釋?zhuān)?/p>
package NIOTest;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/**
* NIO
* Created by AceCream on 2017/5/12.
*/
public class TestChannel {
public static void main(String[] args) throws IOException {
/**
*
* RandomAccessFile是用來(lái)訪問(wèn)那些保存數(shù)據(jù)記錄的文件的,
* 你就可以用seek( )方法來(lái)訪問(wèn)記錄,并進(jìn)行讀寫(xiě)了。這些記錄的大小不必相同;
* !但是其大小和位置必須是可知的。但是該類(lèi)僅限于操作文件。!
* RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream結(jié)合起來(lái),
* 再加上它自己的一些方法
*/
Charset charset = Charset.forName("UTF-8");
//解碼器
CharsetDecoder decoder = charset.newDecoder();
RandomAccessFile aFile = new RandomAccessFile("nio-data.txt","rw");
//獲取Channel
FileChannel inChannel = aFile.getChannel();
//創(chuàng)建一個(gè)容量為256字節(jié)的ByteBuffer
ByteBuffer buf = ByteBuffer.allocate(48);
//創(chuàng)建一個(gè)容量為256字節(jié)的CharBuffer
CharBuffer cb = CharBuffer.allocate(48);
// System.out.println("ByteBuffer信息:"+buf);
int count = inChannel.read(buf);
while (count!=-1){
System.out.println("count= "+count);
//注意 buf.flip() 的調(diào)用,首先讀取數(shù)據(jù)到Buffer,然后反轉(zhuǎn)Buffer,接著再?gòu)腂uffer中讀取數(shù)據(jù)。
buf.flip();
//用解碼器進(jìn)行解碼
decoder.decode(buf, cb, false);
//解碼后,charbuffer再flip一下
cb.flip();
//這里為了避免中文亂碼問(wèn)題,采用CharBuffer,通過(guò)設(shè)置CharSet字符集,將byte編碼成char去測(cè)試
while (cb.hasRemaining()){
System.out.print(cb.get());
}
buf.clear();
cb.clear();
count = inChannel.read(buf);
System.out.println();
}
//RandomAccessFile的close方法會(huì)將對(duì)應(yīng)的非空channel關(guān)閉。
aFile.close();
}
}
做一些解釋?zhuān)?br>
Q:為什么不關(guān)閉Channel?
A:因?yàn)殛P(guān)閉了RandomAccessFile,同時(shí)就關(guān)閉了非空的Channel~