Java NIO 是Java1.4版本推出的新的IO接口,全稱Java Non-BlockingIO,也有人稱之為Java New IO。從其名稱可以看出它是有別與Java 標(biāo)準(zhǔn)IO的,Non-blocking(非阻塞)道明了其主要特征。
Java標(biāo)準(zhǔn)io中,我們在使用的時候的流程是這樣的,先創(chuàng)建一個InputStream,將數(shù)據(jù)寫入InputStream,將InputStream中的數(shù)據(jù)讀入一個字節(jié)數(shù)組中,然后創(chuàng)建一個OutputSteam,從字節(jié)數(shù)組中讀取數(shù)據(jù)到OutputStream中,然后調(diào)用write方法寫到目標(biāo),它是基于字節(jié)的,所有的io都被視為單個字節(jié)的移動。然而Nio卻卻別于這一過程,在NIO中,增加了channel,buffer,selector的概念,NIO的使用流程變成了這樣,先創(chuàng)建一個channel,將channel中的數(shù)據(jù)讀入buffer中,寫數(shù)據(jù)時將buffer中的數(shù)據(jù)寫入channel中即可。它是基于塊的,這個塊可以理解成就是那個buffer,buffer從channel中獲取數(shù)據(jù)并運(yùn)輸,我們獲取數(shù)據(jù)直接從buffer中獲取。
下面來看看代碼怎么實(shí)現(xiàn)。將一個字符串寫入一個文件中。
//先在src路徑下創(chuàng)建一個文件,獲取outputStream
FileOutputStream fileOutStream =newFileOutputStream("src/JavaNio.txt");
//通過outputStream獲取channel
FileChannel fileChannel = fileOutputStream.getChannel();
//創(chuàng)建一個buffer,并將要寫到文件中的數(shù)據(jù)放入buffer中
ByteBuffer bb = ByteBuffer.allocate(1024);
String s ="Hello World!";
bb.put(s.getBytes());
//反轉(zhuǎn)buffer,使其可讀,很重要,個人覺得這個操作很惡心
bb.flip();
//然后寫入通道
fileChannel.write(bb);
此時數(shù)據(jù)已經(jīng)寫入到文件中去了
從文件中讀取字符串。
//獲取channel
FileInputStream fileInputStream =newFileInputStream("src/JavaNio.txt");
FileChannel fileChannel = fileInputStream.getChannel();
//創(chuàng)建buffer并將channel中的數(shù)據(jù)寫入buffer中
ByteBuffer bb = ByteBuffer.allocate(1024);
fileChannel.read(bb);
//反轉(zhuǎn)buffer,并從buffer中獲取一個字節(jié)數(shù)組
bb.flip();
//注意這里,這個字節(jié)數(shù)組的長度不要大于buffer中的數(shù)據(jù)長度,buffer讀模式中l(wèi)imit代表這個buffer中有多少數(shù)據(jù)可以讀。如果大了會拋出一個BufferUnderflowException。
byte[] b =new byte[bb.limit()];
String s = new String[b]
NIO socket使用。和標(biāo)準(zhǔn)io一樣,nio的socket也分為ServerSocketChannel和SocketChannel。在標(biāo)準(zhǔn)io的socket通信中,server端每獲取一個client端連接的時候會新開一條線程,在這個線程中來處理消息。NIO中你不必這樣,NIO有一個Selector的概念,每個channel(不論是server端還是client端)注冊到selector中后,selector會輪詢這些channel,如果有數(shù)據(jù),則進(jìn)行數(shù)據(jù)處理,不需要我們手動去新開線程。
看看代碼怎么做吧。
server.java ?main()
//開啟selector
Selector selector = Selector.open();
//創(chuàng)建serversocketchannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(newInetSocketAddress(8765));
//設(shè)置非阻塞,并將serversocketchannel注冊到selector中,這里的SelectionKey.OP_ACCEPT表示這個channel已經(jīng)準(zhǔn)備好接受連接了
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
//然后遍歷selector中的所有的channel
while(selector.select()>0){
for(SelectionKey key : selector.selectedKeys()){
//獲取當(dāng)前的key,這個key對應(yīng)著一個channel,serverchannel和clientchannel都在其中,獲取到之后就可以將其移除了。
selector.selectedKeys().remove(key);
//如果key是Acceptable,還記得serverchannel注冊到seletor中時設(shè)置的key不。
if(key.isAcceptable()){
//通過serverChannel獲取連接上的具體的clientChannel,就跟標(biāo)準(zhǔn)io中serversocket.accept()一樣返回的是客戶端的socket
SocketChannel sc = serverSocketChannel.accept();
//獲取到客戶端的channel后設(shè)置非阻塞并注冊到selector中。
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
}
//isReadable表示一個clientChannel已經(jīng)準(zhǔn)備好數(shù)據(jù)了,在這里進(jìn)行數(shù)據(jù)處理
if(key.isReadable()){
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// String content = "";
while(sc.read(byteBuffer)>0){
byteBuffer.flip();
System.out.println(newString(byteBuffer.array(),"utf-8"));}
key.interestOps(SelectionKey.OP_READ);}}}
client.java main()
SocketChannel sc = SocketChannel.open();
sc.connect(newInetSocketAddress("127.0.0.1",8765));
while(true) {
byte[] bytes =new byte[1024];
System.in.read(bytes);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.put(bytes);
byteBuffer.flip();
//將buffer中的數(shù)據(jù)寫入到channel中
sc.write(byteBuffer);
byteBuffer.clear();
好了JavaNIO的使用我就寫這么多了,更多更詳細(xì)的內(nèi)容自行百度。對文中有不對的地方歡迎提出指正。