Java NIO主要需要理解緩衝區(qū)、通道、選擇器三個(gè)核心概念,作為Java I/O的補(bǔ)充, 以提升大量資料傳輸?shù)男省?
(推薦教學(xué):java課程)
學(xué)習(xí)NIO之前最好能有基礎(chǔ)的網(wǎng)路程式設(shè)計(jì)知識
Java I/O串流
Java 網(wǎng)路程式設(shè)計(jì)
Java NIO:緩衝區(qū)
通道(Channel)作為NIO的三大核心概念之一(緩衝區(qū)、通道、選擇器),用於在位元組緩衝區(qū)與位於通道另一側(cè)的實(shí)體(檔案或套接字)之間有效的傳輸資料(核心是傳輸資料)
NIO程式設(shè)計(jì)的一般模式是:將資料填入傳送字節(jié)緩衝區(qū)--> 透過通道傳送到通道對端檔案或套接字
通道基礎(chǔ)
使用Channel的目的是進(jìn)行資料傳輸,使用前需要打開通道、使用後需要關(guān)閉通道
打開通道
我們知道I/O有兩大類:File IO和Stream I/O,其對應(yīng)到通道也就有檔案通道(FileChannel)和套接字通道(SocketChannel、ServerSocketChannel、DatagramChannel)兩種
對於套接字通道,使用靜態(tài)工廠方法開啟
SocketChannel sc = SocketChannel.open(); ServerSocketChannel sc = ServerSocketChannel.open(); DatagramChannel sc = DatagramChannel.open();
對於檔案通道只能透過對一個(gè)RandomAccessFile、FileInputStream、FileOutputStream物件呼叫g(shù)etChannel()方法取得
FileInputStream in = new FileInputStream("/tmp/a.txt"); FileChannel fc = in.getChannel();
使用通道進(jìn)行資料傳輸
下段程式碼首先將要寫入的資料放到ByteBuffer中, 然後開啟檔案通道,把緩衝區(qū)中的資料放到檔案通道。
//準(zhǔn)備數(shù)據(jù)并放入字節(jié)緩沖區(qū) ByteBuffer bf = ByteBuffer.allocate(1024); bf.put("i am cool".getBytes()); bf.flip(); //打開文件通道 FileOutputStream out = new FileOutputStream("/tmp/a.txt"); FileChannel fc = out.getChannel(); //數(shù)據(jù)傳輸 fc.write(bf); //關(guān)閉通道 fc.close();
關(guān)閉通道
如同Socket、FileInputStream等物件使用完畢之後需要關(guān)閉一樣, 通道使用之後也需要關(guān)閉。一個(gè)打開的通道代表與一個(gè)特定I/O服務(wù)的特定連接並封裝該連接的狀態(tài),通道關(guān)閉時(shí)連接丟失,不再連接任何東西。
阻塞& 非阻塞模式
通道有阻塞和非阻塞兩種運(yùn)作模式,非阻塞模式的通道永遠(yuǎn)不會(huì)休眠,請求的操作要麼立即完成,要么返回一個(gè)結(jié)果表明未進(jìn)行任何操作(具體看Socket通道處的描述)。只有面向流的通道可使用非阻塞模式
文件通道
文件通道用於對文件進(jìn)行訪問, 透過對一個(gè)RandomAccessFile、FileInputStream、FileOutputStream物件呼叫g(shù)etChannel ()方法取得。呼叫g(shù)etChannel方法傳回一個(gè)連接到相同檔案的FileChannel對象,該FileChannel物件具有與file對象相同的存取權(quán)。
檔案存取
使用檔案通道的目的還是對檔案進(jìn)行讀寫操作,通道的讀寫api如下:
public abstract int read(ByteBuffer dst) throws IOException; public abstract int write(ByteBuffer src) throws IOException;
下面是一段讀取檔案的Demo
//打開文件channel RandomAccessFile f = new RandomAccessFile("/tmp/a.txt", "r"); FileChannel fc = f.getChannel(); //從channel中讀取數(shù)據(jù),直到文件尾 ByteBuffer bb = ByteBuffer.allocate(1024); while (fc.read(bb) != -1) { ; } //翻轉(zhuǎn)(讀之前需要先進(jìn)行翻轉(zhuǎn)) bb.flip(); StringBuilder builder = new StringBuilder(); //把每一個(gè)字節(jié)轉(zhuǎn)為字符(ascii編碼) while (bb.hasRemaining()) { builder.append((char) bb.get()); } System.out.println(builder.toString());
上面這個(gè)demo有個(gè)問題:我們只能讀取字節(jié), 然後由應(yīng)用程式去解碼,這個(gè)問題我們可以透過工具類Channels將通道包裝成Reader和Writer來解決;當(dāng)然我們也可以直接使用Java I/O流模式的Reader和Writer操作字符
#文件通道位置與文件空洞
文件通道位置(position)就是普通檔案的位置, position的值決定了檔案中哪個(gè)位置的資料接下來將被讀取或?qū)懭?/p>
#讀取超出檔案尾部位置的資料會(huì)回傳-1(檔案EOF)
往一個(gè)超出檔案尾部的位置寫入資料會(huì)造成檔案空洞:例如一個(gè)檔案現(xiàn)在有10個(gè)位元組, 但是此時(shí)往position=20 處寫入資料就會(huì)造成10~20之間的位置是沒有資料的,這就是檔案空洞
force操作
force操作強(qiáng)制通道將全部修改立即套用到磁碟檔案(防止系統(tǒng)宕機(jī)導(dǎo)致修改遺失)
public abstract void force(boolean metaData) throws IOException;
記憶體檔案對應(yīng)
FileChannel提供了一個(gè)map()方法,可以在一個(gè)開啟的檔案和特殊類型的ByteBuffer(MappedByteBuffer)之間建立一個(gè)虛擬記憶體映射。
因?yàn)閙ap方法傳回的MappedByteBuffer物件是直接緩衝區(qū),所以透過MappedByteBuffer來操作檔案非常有效率(尤其是大量資料傳輸?shù)那闆r)
MappedByteBuffer的使用
透過MappedByteBuffer讀取檔案
FileInputStream in = new FileInputStream("/tmp/a.txt"); FileChannel fc = in.getChannel(); MappedByteBuffer mbb = fc.map(MapMode.READ_ONLY, 0, fc.size()); StringBuilder builder = new StringBuilder(); while (mbb.hasRemaining()) { builder.append((char) mbb.get()); } System.out.println(builder.toString());
MappedByteBuffer的三種模式
READ_ONLY
#READ_WRITE
PRIVATE
只讀和讀寫模式都好理解,PRIVATE模式下寫操作寫的是一個(gè)暫存緩衝區(qū),不會(huì)真正去寫檔案。 (寫時(shí)拷貝思想)
Socket通道
Socket 通道可以運(yùn)行在非阻塞模式且是可選擇的,這兩點(diǎn)使得對於網(wǎng)路程式設(shè)計(jì)我們不再需要為每個(gè)Socket連線建立一個(gè)線程,而是使用一個(gè)線程即可管理成百上千的Socket連線。
所有的Socket通道在實(shí)例化的時(shí)候都會(huì)創(chuàng)建一個(gè)對象的Socket對象, Socket通道並不負(fù)責(zé)協(xié)議相關(guān)的操作, 協(xié)議相關(guān)的操作都委派給對等socket對象(如SocketChannel對象委派給Socket物件)
非阻塞模式
相較于傳統(tǒng)Java Socket的阻塞模式,SocketChannel提供了非阻塞模式,以構(gòu)建高性能的網(wǎng)絡(luò)應(yīng)用程序
非阻塞模式下,幾乎所有的操作都是立刻返回的。比如下面的SocketChannel運(yùn)行在非阻塞模式下,connect操作會(huì)立即返回,如果success為true代表連接已經(jīng)建立成功了, 如果success為false, 代表連接還在建立中(tcp連接需要一些時(shí)間)。
//打開Socket通道 SocketChannel ch = SocketChannel.open(); //非阻塞模式 ch.configureBlocking(false); //連接服務(wù)器 boolean success = ch.connect(InetSocketAddress.createUnresolved("127.0.0.1", 7001)); //輪訓(xùn)連接狀態(tài), 如果連接還未建立就可以做一些別的工作 while (!ch.finishConnect()){ //dosomething else } //連接建立, 做正事 //do something;
ServerSocketChannel
ServerSocketChannel與ServerSocket類似,只是可以運(yùn)行在非阻塞模式下
下為一個(gè)通過ServerSocketChannel構(gòu)建服務(wù)器的簡單例子,主要體現(xiàn)了非阻塞模式,核心思想與ServerSocket類似
ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); ssc.bind(new InetSocketAddress(7001)); while (true){ SocketChannel sc = ssc.accept(); if(sc != null){ handle(sc); }else { Thread.sleep(1000); } }
SocketChannel 與 DatagramChannel
SocketChannel 對應(yīng) Socket, 模擬TCP協(xié)議;DatagramChannel對應(yīng)DatagramSocket, 模擬UDP協(xié)議
二者的使用與SeverSocketChannel大同小異,看API即可
工具類
文體通道那里我們提到過, 通過只能操作字節(jié)緩沖區(qū), 編解碼需要應(yīng)用程序自己實(shí)現(xiàn)。如果我們想在通道上直接操作字符,我們就需要使用工具類Channels,工具類Channels提供了通道與流互相轉(zhuǎn)換、通道轉(zhuǎn)換為閱讀器書寫器的能力,具體API入下
//通道 --> 輸入輸出流 public static OutputStream newOutputStream(final WritableByteChannel ch); public static InputStream newInputStream(final AsynchronousByteChannel ch); //輸入輸出流 --> 通道 public static ReadableByteChannel newChannel(final InputStream in); public static WritableByteChannel newChannel(final OutputStream out); //通道 --> 閱讀器書寫器 public static Reader newReader(ReadableByteChannel ch, String csName); public static Writer newWriter(WritableByteChannel ch, String csName);
通過將通道轉(zhuǎn)換為閱讀器、書寫器我們就可以直接在通道上操作字符。
RandomAccessFile f = new RandomAccessFile("/tmp/a.txt", "r"); FileChannel fc = f.getChannel(); //通道轉(zhuǎn)換為閱讀器,UTF-8編碼 Reader reader = Channels.newReader(fc, "UTF-8"); int i = 0, s = 0; char[] buff = new char[1024]; while ((i = reader.read(buff, s, 1024 - s)) != -1) { s += i; } for (i = 0; i < s; i++) { System.out.print(buff[i]); }
總結(jié)
通道主要分為文件通道和套接字通道。
對于文件操作:如果是大文件使用通道的文件內(nèi)存映射特性(MappedByteBuffer)來有利于提升傳輸性能, 否則我更傾向傳統(tǒng)的I/O流模式(字符API);對于套接字操作, 使用通道可以運(yùn)行在非阻塞模式并且是可選擇的,利于構(gòu)建高性能網(wǎng)絡(luò)應(yīng)用程序。
相關(guān)推薦:java入門
以上是詳細(xì)介紹Java NIO的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)
