亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

java的nio的使用示例分享

2019-11-26 15:34:35
字體:
來源:轉載
供稿:網友

Java NIO(New Input/Output)――新的輸入/輸出API包――是2002年引入到J2SE 1.4里的。Java NIO的目標是提高Java平臺上的I/O密集型任務的性能。過了十年,很多Java開發者還是不知道怎么充分利用NIO,更少的人知道在Java SE 7里引入了更新的輸入/輸出 API(NIO.2)。NIO和NIO.2對于Java平臺最大的貢獻是提高了Java應用開發中的一個核心組件的性能:輸入/輸出處理。不過這兩個包都不是很好用,并且它們也不是適用于所有的場景。如果能夠正確地使用的話,Java NIO和NIO.2可以大大減少一些常用I/O操作所花的時間。這就是NIO和NIO.2所具有的超能力,我會在這篇文章里向你展示5種使用它們的簡單方式。

變更通知(因為每個事件都需要一個監聽者)
選擇器和異步IO:通過選擇器來提高多路復用
通道――承諾與現實
內存映射――好鋼用在刀刃上
字符編碼和搜索
NIO的背景

為什么一個已經存在10年的增強包還是Java的新I/O包呢?原因是對于大多數的Java程序員而言,基本的I/O操作都能夠勝任。在日常工作中,大部分的Java開發者沒有必要去學習NIO。更進一步,NIO不僅僅是一個性能提升包。相反,它是一個和Java I/O相關的不同功能的集合。NIO通過使得Java應用的性能“更加接近實質”來達到性能提升的效果,也就是意味著NIO和NIO.2的API暴露了低層次的系統操作的入口。NIO的代價就是它在提供更強大的I/O控制能力的同時,也要求我們比使用基本的I/O編程更加細心地使用和練習。NIO的另一特點是它對于應用程序的表現力的關注,這個我們會在下面的練習中看到。

開始學習NIO和NIO.2

NIO的參考資料非常多――參考資料中選取的一些鏈接。要學習NIO和NIO.2的話,Java 2 SDK Standard Edition(SE) documentation 和 Java SE 7 documentation 都是不可或缺的。要使用這篇文章里的代碼,你需要使用JDK 7或者更高的版本。

對于很多開發者而言,它們第一次遇到NIO都可能是在維護應用的時候:一個功能正常的應用響應越來越慢,因此有人建議使用NIO來提高響應速度。NIO在提升應用性能的時候顯得比較出眾,不過具體的結果取決于底層系統.(注意NIO是平臺相關的)。如果你是第一次使用NIO的話,你需要仔細衡量。你會發現NIO提升性能的能力不僅僅取決于OS,同時也取決于你所使用的JVM,主機的虛擬上下文,大容量存儲的特性甚至和數據也是相關的。因此,性能衡量的工作是比較難做的。尤其是當你的系統存在一個可移動的部署環境的時候,你需要特別注意。

了解了上面的內容后,我們沒有后顧之憂了,現在就來體驗一下NIO和NIO.2的5個重要的功能。

1. 變更通知(因為每個事件都需要一個監聽者)

對NIO和NIO.2有興趣的開發者的共同關注點在于Java應用的性能。根據我的經驗,NIO.2里的文件變更通知者(file change notifier)是新輸入/輸出API里最讓人感興趣(被低估了)的特性。

很多企業級應用需要在下面的情況時做一些特殊的處理:

當一個文件上傳到一個FTP文件夾里時
當一個配置里的定義被修改時
當一個草稿文檔被上傳時
其他的文件系統事件出現時
這些都是變更通知或者變更響應的例子。在Java(以及其他語言)的早期版本里,輪詢(polling)是檢測這些變更事件的最好方式。輪詢是一種特殊的無限循環:檢查文件系統或者其他對象,并且和之前的狀態對比,如果沒有變化,在大概幾百個毫秒或者10秒的間隔后,繼續檢查。就這一直無限循環下去。

NIO.2提供了一個更好地方式來進行變更檢測。列表1是一個簡單的示例。

列表1. NIO.2里的變更通知機制

復制代碼 代碼如下:

import java.nio.file.attribute.*;
importjava.io.*;
importjava.util.*;
importjava.nio.file.Path;
importjava.nio.file.Paths;
importjava.nio.file.StandardWatchEventKinds;
importjava.nio.file.WatchEvent;
importjava.nio.file.WatchKey;
importjava.nio.file.WatchService;
importjava.util.List;

publicclassWatcher{
publicstaticvoidmain(String[]args){
Paththis_dir=Paths.get(".");
System.out.println("Nowwatchingthecurrentdirectory...");

try{
WatchServicewatcher=this_dir.getFileSystem().newWatchService();
this_dir.register(watcher,StandardWatchEventKinds.ENTRY_CREATE);

WatchKeywatckKey=watcher.take();

List<WatchEvent<<64;>>events=watckKey.pollEvents();
for(WatchEventevent:events){
System.out.println("Someonejustcreatedthefile'"+event.context().toString()+"'.");

}

}catch(Exceptione){
System.out.println("Error:"+e.toString());
}
}
}

編譯這段代碼,然后在命令行里執行。在相同的目錄下,創建一個新的文件,例如運行touchexample或者copyWatcher.classexample命令。你會看到下面的變更通知消息:

Someonejustcreatethefiel‘example1′.


這個簡單的示例展示了怎么開始使用JavaNIO的功能。同時,它也介紹了NIO.2的Watcher類,它相比較原始的I/O中的輪詢方案而言,顯得更加直接和易用。

注意拼寫錯誤

當你從這篇文章里拷貝代碼時,注意拼寫錯誤。例如,列表1種的StandardWatchEventKinds對象是復數的形式。即使在Java.net的文檔里都把它給拼寫錯了。

小技巧

NIO里的通知機制比老的輪詢方式使用起來更加簡單,這樣會誘導你忽略對具體需求的詳細分析。當你在你第一次使用一個監聽器的時候,你需要仔細考慮你所使用的這些概念的語義。例如,知道一個變更什么時候會結束比知道它什么時候開始更加重要。這種分析需要非常仔細,尤其是像移動FTP文件夾這種常見的場景。NIO是一個功能非常強大的包,但同時它還會有一些微妙的“陷阱”,這會給那些不熟悉它的人帶來困擾。

2.選擇器和異步IO:通過選擇器來提高多路復用

NIO新手一般都把它和“非阻塞輸入/輸出”聯系在一起。NIO不僅僅只是非阻塞I/O,不過這種認知也不完全是錯的:Java的基本I/O是阻塞式I/O――意味著它會一直等待到操作完成――然而,非阻塞或者異步I/O是NIO里最常用的一個特點,而非NIO的全部。

NIO的非阻塞I/O是事件驅動的,并且在列表1里文件系統監聽示例里進行了展示。這就意味著給一個I/O通道定義一個選擇器(回調或者監聽器),然后程序可以繼續運行。當一個事件發生在這個選擇器上時――例如接收到一行輸入――選擇器會“醒來”并且執行。所有的這些都是通過一個單線程來實現的,這和Java的標準I/O有著顯著的差別的。

列表2里展示了使用NIO的選擇器實現的一個多端口的網絡程序echo-er,這里是修改了GregTravis在2003年創建的一個小程序(參考資源列表)。Unix和類Unix系統很早就已經實現高效的選擇器,它是Java網絡高性能編程模型的一個很好的參考模型。

列表2.NIO選擇器

復制代碼 代碼如下:

importjava.io.*;
importjava.net.*;
importjava.nio.*;
importjava.nio.channels.*;
importjava.util.*;

publicclassMultiPortEcho
{
privateintports[];
privateByteBufferechoBuffer=ByteBuffer.allocate(1024);

publicMultiPortEcho(intports[])throwsIOException{
this.ports=ports;

configure_selector();
}

privatevoidconfigure_selector()throwsIOException{
//Createanewselector
Selectorselector=Selector.open();

//Openalisteneroneachport,andregistereachone
//withtheselector
for(inti=0;i<ports.length;++i){
ServerSocketChannelssc=ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocketss=ssc.socket();
InetSocketAddressaddress=newInetSocketAddress(ports[i]);
ss.bind(address);

SelectionKeykey=ssc.register(selector,SelectionKey.OP_ACCEPT);

System.out.println("Goingtolistenon"+ports[i]);
}

while(true){
intnum=selector.select();

SetselectedKeys=selector.selectedKeys();
Iteratorit=selectedKeys.iterator();

while(it.hasNext()){
SelectionKeykey=(SelectionKey)it.next();

if((key.readyOps()&SelectionKey.OP_ACCEPT)
==SelectionKey.OP_ACCEPT){
//Acceptthenewconnection
ServerSocketChannelssc=(ServerSocketChannel)key.channel();
SocketChannelsc=ssc.accept();
sc.configureBlocking(false);

//Addthenewconnectiontotheselector
SelectionKeynewKey=sc.register(selector,SelectionKey.OP_READ);
it.remove();

System.out.println("Gotconnectionfrom"+sc);
}elseif((key.readyOps()&SelectionKey.OP_READ)
==SelectionKey.OP_READ){
//Readthedata
SocketChannelsc=(SocketChannel)key.channel();

//Echodata
intbytesEchoed=0;
while(true){
echoBuffer.clear();

intnumber_of_bytes=sc.read(echoBuffer);

if(number_of_bytes<=0){
break;
}

echoBuffer.flip();

sc.write(echoBuffer);
bytesEchoed+=number_of_bytes;
}

System.out.println("Echoed"+bytesEchoed+"from"+sc);

it.remove();
}

}
}
}

staticpublicvoidmain(Stringargs[])throwsException{
if(args.length<=0){
System.err.println("Usage:javaMultiPortEchoport[portport...]");
System.exit(1);
}

intports[]=newint[args.length];

for(inti=0;i<args.length;++i){
ports[i]=Integer.parseInt(args[i]);
}

newMultiPortEcho(ports);
}
}

編譯這段代碼,然后通過類似于javaMultiPortEcho80058006這樣的命令來啟動它。一旦這個程序運行成功,啟動一個簡單的telnet或者其他的終端模擬器來連接8005和8006接口。你會看到這個程序會回顯它接收到的所有字符――并且它是通過一個Java線程來實現的。

3.通道:承諾與現實

在NIO里,一個通道(channel)可以表示任何可以讀寫的對象。它的作用是為文件和套接口提供抽象。NIO通道支持一系列一致的方法,這樣就使得編碼的時候不需要去特別關心不同的對象,無論它是標準輸出,網絡連接還是正在使用的通道。通道的這個特性是繼承自Java基本I/O中的流(stream)。流(stream)提供了阻塞式的IO;通道支持異步I/O。

NIO經常會因為它的性能高而被推薦,不過更準確地是因為它的響應快速。在有些場景下NIO會比基本的JavaI/O的性能要差。例如,對于一個小文件的簡單的順序讀寫,簡單通過流來實現的性能可能比對應的面向事件的基于通道的編碼實現的快兩到三倍。同時,非多路復用(non-multiplex)的通道――也就是每個線程一個單獨的通道――要比多個通道把各自的選擇器注冊在同一個線程里要慢多了。

下面你在考慮是使用流還是通道的時候,試著問自己下面幾個問題:

你需要讀寫多少個I/O對象?
不同的I/O對象直接是否有有順序,還是他們都需要同時發生的?
你的I/O對象是需要持續一小段時間還是在你的進程的整個聲明周期都存在?
你的I/O是適合在單個線程里處理還是在幾個不同的線程里?
網絡通信和本地I/O是看起來一樣,還是各自有著不同的模式?
這樣的分析是決定使用流還是通道的一個最佳實踐。記?。篘IO和NIO.2不是基本I/O的替代,而它的一個補充。

4.內存映射――好鋼用在刀刃上

NIO里對性能提升最顯著的是內存映射(memorymapping)。內存映射是一個系統層面的服務,它把程序里用到的文件的一段當作內存來處理。

內存映射存在很多潛在的影響,比我這里提供的要多。在一個更高的層次上,它能夠使得文件訪問的I/O的性能達到內存訪問的速度。內存訪問的速度往往比文件訪問的速度快幾個數量級。列表3是一個NIO內存映射的一個簡單示例。

列表3.NIO里的內存映射

復制代碼 代碼如下:

importjava.io.RandomAccessFile;
importjava.nio.MappedByteBuffer;
importjava.nio.channels.FileChannel;

publicclassmem_map_example{
privatestaticintmem_map_size=20*1024*1024;
privatestaticStringfn="example_memory_mapped_file.txt";

publicstaticvoidmain(String[]args)throwsException{
RandomAccessFilememoryMappedFile=newRandomAccessFile(fn,"rw");

//Mappingafileintomemory
MappedByteBufferout=memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE,0,mem_map_size);

//WritingintoMemoryMappedFile
for(inti=0;i<mem_map_size;i++){
out.put((byte)'A');
}
System.out.println("File'"+fn+"'isnow"+Integer.toString(mem_map_size)+"bytesfull.");

//Readfrommemory-mappedfile.
for(inti=0;i<30;i++){
System.out.print((char)out.get(i));
}
System.out.println("/nReadingfrommemory-mappedfile'"+fn+"'iscomplete.");
}
}

在列表3中,這個簡單的示例創建了一個20M的文件example_memory_mapped_file.txt,并且用字符A對它進行填充,然后讀取前30個字節。在實際的應用中,內存映射不僅僅擅長提高I/O的原始速度,同時它也允許多個不同的reader和writer同時處理同一個文件鏡像。這個技術功能強大但是也很危險,不過如果正確使用的話,它會使得你的IO速度提高數倍。眾所周知,華爾街的交易操作為了能夠贏得秒級甚至是毫秒級的優勢,都使用了內存映射技術。

5.字符編碼和搜索

我在這篇文章里要講解的NIO的最后一個特性是charset,一個用來轉換不同字符編碼的包。在NIO之前,Java通過getByte方法內置實現了大部分相同的功能。charset很受歡迎,因為它比getBytes更加靈活,并且能夠在更底層去實現,這樣就能夠獲得更好的性能。這個對于搜索那些對于編碼、順序以及其他語言特點比較敏感的非英語語言而言更加有價值。

列表4展示了一個把Java里的Unicode字符轉換成Latin-1的示例

列表4.NIO里的字符

復制代碼 代碼如下:

Stringsome_string="ThisisastringthatJavanativelystoresasUnicode.";
Charsetlatin1_charset=Charset.forName("ISO-8859-1");
CharsetEncodelatin1_encoder=charset.newEncoder();
ByteBufferlatin1_bbuf=latin1_encoder.encode(CharBuffer.wrap(some_string));

注意Charset和通道被設計成能夠放在一起進行使用,這樣就能夠使得程序在內存映射、異步I/O以及編碼轉換進行協作的時候,能夠正常運行。

總結:當然還有更多需要去了解

這篇文章的目的是為了讓Java開發者能夠熟悉NIO和NIO.2里的一些最主要(也是最有用)的功能。你可以通過這些示例建立起來的一些基礎來理解NIO的一些其他方法;例如,你所學習的關于通道的知識能夠幫助你去理解NIO的Path里對于文件系統里的符號鏈接的處理。你也可以參考一下我后面給出的資源列表,里面給出了一些深入學習Java新I/OAPI的文檔。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人精品一区二区在线| 欧美在线亚洲在线| 日韩中文理论片| 日韩精品高清在线| 欧美精品久久久久久久免费观看| 日韩av在线天堂网| 亚洲xxxx做受欧美| 日本不卡免费高清视频| 亚洲最大福利网| 国产精品自产拍在线观看| 91在线色戒在线| 97人人做人人爱| 亚洲天堂男人天堂| 亚洲无av在线中文字幕| 亚洲欧美中文另类| www.xxxx精品| 欧美极品美女电影一区| 久久在线精品视频| 国产精品久久久久久中文字| 成人啪啪免费看| 欧美日韩国产综合视频在线观看中文| 色小说视频一区| 成人黄色影片在线| 成人av资源在线播放| 亚洲成人av在线| 欧美日韩国产一区在线| 国产精品青草久久久久福利99| 亚洲japanese制服美女| 国产成人高潮免费观看精品| 国内精品久久久久影院优| 69av视频在线播放| 亚洲美腿欧美激情另类| 韩曰欧美视频免费观看| 精品国产鲁一鲁一区二区张丽| 欧美人在线观看| 欧美性感美女h网站在线观看免费| 尤物tv国产一区| 一本大道久久加勒比香蕉| 日韩av电影手机在线观看| 青青在线视频一区二区三区| 国产精品直播网红| 欧美激情区在线播放| 国产精品中文字幕在线观看| 5252色成人免费视频| 91免费国产网站| 国产一区二区色| 欧美裸体视频网站| 亚洲国产美女久久久久| 96精品久久久久中文字幕| 欧美极品美女视频网站在线观看免费| 国内精品视频在线| 九九热99久久久国产盗摄| 欧美裸体xxxxx| 日韩美女视频在线观看| 亚洲国产又黄又爽女人高潮的| 国模叶桐国产精品一区| 91精品免费看| 亚洲自拍偷拍视频| 亚洲欧美另类中文字幕| 色av中文字幕一区| 欧美人与物videos| 最近中文字幕mv在线一区二区三区四区| 日韩精品免费在线观看| 国内精品久久久久久中文字幕| 欧美丰满老妇厨房牲生活| 在线观看精品国产视频| 国产精品∨欧美精品v日韩精品| 成人国产精品久久久久久亚洲| 欧美激情视频网址| 国产精品久久久久久久久免费| 久久精品视频在线| 成人免费网视频| 欧美电影免费观看大全| 久久久免费在线观看| 亚洲精品电影网站| 欧美精品午夜视频| 国模精品视频一区二区三区| 欧洲亚洲免费视频| 欧美中文字幕在线播放| 亚洲欧美成人精品| 亚洲欧美制服第一页| 国产精品美腿一区在线看| 国产精品久久久久不卡| 中文字幕亚洲天堂| 国产精品丝袜一区二区三区| 国产成人中文字幕| 91热福利电影| 中文字幕亚洲色图| 日韩精品在线看| 日韩在线视频网| 国产精品久久久久久久7电影| 国产视频精品va久久久久久| 日韩在线一区二区三区免费视频| 疯狂欧美牲乱大交777| 精品国产拍在线观看| 色yeye香蕉凹凸一区二区av| 亚洲级视频在线观看免费1级| 欧美亚洲激情在线| 国产欧美精品久久久| 亚洲香蕉av在线一区二区三区| 亚洲福利视频网站| 亚洲一区av在线播放| 亚洲精品欧美日韩| 国产精品第100页| 欧美一区二三区| 欧美资源在线观看| 午夜精品久久17c| 欧美性猛交99久久久久99按摩| 91免费高清视频| 日韩激情av在线播放| 姬川优奈aav一区二区| 中文.日本.精品| 爽爽爽爽爽爽爽成人免费观看| 亚洲精品按摩视频| 91国产精品91| 国产亚洲一区二区在线| 国产69精品久久久久9| 亚洲老板91色精品久久| 欧美日韩精品二区| 成人久久一区二区| 国产精品精品久久久| 久久久99免费视频| 2019中文字幕免费视频| 亚洲人线精品午夜| 亚洲精品99久久久久中文字幕| 国产精品女人久久久久久| 久久99亚洲热视| 国内免费久久久久久久久久久| 亚洲国产精品国自产拍av秋霞| 69国产精品成人在线播放| 亚洲精品一区久久久久久| 日本精品久久久| 亚洲欧美日韩一区二区在线| 国产激情综合五月久久| 亚洲色图日韩av| 欧洲成人免费视频| 久久久久www| 久久久在线视频| 一本色道久久88精品综合| 亚洲国产91色在线| 精品亚洲一区二区三区| 精品国产一区二区三区在线观看| 色婷婷亚洲mv天堂mv在影片| 久久99热这里只有精品国产| 国产精品偷伦视频免费观看国产| 久久香蕉精品香蕉| 欧美亚洲在线观看| 国产亚洲精品一区二555| 美女啪啪无遮挡免费久久网站| 4444欧美成人kkkk| 亚洲欧美激情精品一区二区| 影音先锋欧美在线资源| 在线不卡国产精品| 欧美激情亚洲视频| 国产精品香蕉在线观看| 欧美黄色www| 欧美成年人视频网站欧美| 91久久在线视频| 久久香蕉频线观| 最近免费中文字幕视频2019| 成人伊人精品色xxxx视频| 自拍亚洲一区欧美另类| 国产亚洲一区二区在线| 欧美成人午夜激情在线|