亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁(yè) Java Java入門(mén) 詳細(xì)介紹Java NIO

詳細(xì)介紹Java NIO

Oct 21, 2020 pm 04:35 PM
java nio

詳細(xì)介紹Java NIO

Java NIO主要需要理解緩衝區(qū)、通道、選擇器三個(gè)核心概念,作為Java I/O的補(bǔ)充, 以提升大量資料傳輸?shù)男省?

(推薦教學(xué):java課程

學(xué)習(xí)NIO之前最好能有基礎(chǔ)的網(wǎng)路程式設(shè)計(jì)知識(shí)

Java I/O串流

Java 網(wǎng)路程式設(shè)計(jì)

Java NIO:緩衝區(qū)

通道(Channel)作為NIO的三大核心概念之一(緩衝區(qū)、通道、選擇器),用於在位元組緩衝區(qū)與位於通道另一側(cè)的實(shí)體(檔案或套接字)之間有效的傳輸資料(核心是傳輸資料)

NIO程式設(shè)計(jì)的一般模式是:將資料填入傳送字節(jié)緩衝區(qū)--> 透過(guò)通道傳送到通道對(duì)端檔案或套接字

通道基礎(chǔ)

使用Channel的目的是進(jìn)行資料傳輸,使用前需要打開(kāi)通道、使用後需要關(guān)閉通道

打開(kāi)通道

我們知道I/O有兩大類(lèi):File IO和Stream I/O,其對(duì)應(yīng)到通道也就有檔案通道(FileChannel)和套接字通道(SocketChannel、ServerSocketChannel、DatagramChannel)兩種

對(duì)於套接字通道,使用靜態(tài)工廠方法開(kāi)啟

SocketChannel sc = SocketChannel.open();
ServerSocketChannel sc = ServerSocketChannel.open();
DatagramChannel sc = DatagramChannel.open();

對(duì)於檔案通道只能透過(guò)對(duì)一個(gè)RandomAccessFile、FileInputStream、FileOutputStream物件呼叫g(shù)etChannel()方法取得

FileInputStream in = new FileInputStream("/tmp/a.txt");
FileChannel fc = in.getChannel();

使用通道進(jìn)行資料傳輸

下段程式碼首先將要寫(xiě)入的資料放到ByteBuffer中, 然後開(kāi)啟檔案通道,把緩衝區(qū)中的資料放到檔案通道。

//準(zhǔn)備數(shù)據(jù)并放入字節(jié)緩沖區(qū)
ByteBuffer bf = ByteBuffer.allocate(1024);
bf.put("i am cool".getBytes());
bf.flip();
//打開(kāi)文件通道
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è)打開(kāi)的通道代表與一個(gè)特定I/O服務(wù)的特定連接並封裝該連接的狀態(tài),通道關(guān)閉時(shí)連接丟失,不再連接任何東西。

阻塞& 非阻塞模式

通道有阻塞和非阻塞兩種運(yùn)作模式,非阻塞模式的通道永遠(yuǎn)不會(huì)休眠,請(qǐng)求的操作要麼立即完成,要么返回一個(gè)結(jié)果表明未進(jìn)行任何操作(具體看Socket通道處的描述)。只有面向流的通道可使用非阻塞模式

文件通道

文件通道用於對(duì)文件進(jìn)行訪問(wèn), 透過(guò)對(duì)一個(gè)RandomAccessFile、FileInputStream、FileOutputStream物件呼叫g(shù)etChannel ()方法取得。呼叫g(shù)etChannel方法傳回一個(gè)連接到相同檔案的FileChannel對(duì)象,該FileChannel物件具有與file對(duì)象相同的存取權(quán)。

檔案存取

使用檔案通道的目的還是對(duì)檔案進(jìn)行讀寫(xiě)操作,通道的讀寫(xiě)api如下:

public abstract int read(ByteBuffer dst) throws IOException;
public abstract int write(ByteBuffer src) throws IOException;

下面是一段讀取檔案的Demo

//打開(kāi)文件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è)問(wèn)題:我們只能讀取字節(jié), 然後由應(yīng)用程式去解碼,這個(gè)問(wèn)題我們可以透過(guò)工具類(lèi)Channels將通道包裝成Reader和Writer來(lái)解決;當(dāng)然我們也可以直接使用Java I/O流模式的Reader和Writer操作字符

#文件通道位置與文件空洞

文件通道位置(position)就是普通檔案的位置, position的值決定了檔案中哪個(gè)位置的資料接下來(lái)將被讀取或?qū)懭?/p>

#讀取超出檔案尾部位置的資料會(huì)回傳-1(檔案EOF)

往一個(gè)超出檔案尾部的位置寫(xiě)入資料會(huì)造成檔案空洞:例如一個(gè)檔案現(xiàn)在有10個(gè)位元組, 但是此時(shí)往position=20 處寫(xiě)入資料就會(huì)造成10~20之間的位置是沒(méi)有資料的,這就是檔案空洞

force操作

force操作強(qiáng)制通道將全部修改立即套用到磁碟檔案(防止系統(tǒng)宕機(jī)導(dǎo)致修改遺失)

public abstract void force(boolean metaData) throws IOException;

記憶體檔案對(duì)應(yīng)

FileChannel提供了一個(gè)map()方法,可以在一個(gè)開(kāi)啟的檔案和特殊類(lèi)型的ByteBuffer(MappedByteBuffer)之間建立一個(gè)虛擬記憶體映射。

因?yàn)閙ap方法傳回的MappedByteBuffer物件是直接緩衝區(qū),所以透過(guò)MappedByteBuffer來(lái)操作檔案非常有效率(尤其是大量資料傳輸?shù)那闆r)

MappedByteBuffer的使用

透過(guò)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

只讀和讀寫(xiě)模式都好理解,PRIVATE模式下寫(xiě)操作寫(xiě)的是一個(gè)暫存緩衝區(qū),不會(huì)真正去寫(xiě)檔案。 (寫(xiě)時(shí)拷貝思想)

Socket通道

Socket 通道可以運(yùn)行在非阻塞模式且是可選擇的,這兩點(diǎn)使得對(duì)於網(wǎng)路程式設(shè)計(jì)我們不再需要為每個(gè)Socket連線(xiàn)建立一個(gè)線(xiàn)程,而是使用一個(gè)線(xiàn)程即可管理成百上千的Socket連線(xiàn)。

所有的Socket通道在實(shí)例化的時(shí)候都會(huì)創(chuàng)建一個(gè)對(duì)象的Socket對(duì)象, Socket通道並不負(fù)責(zé)協(xié)議相關(guān)的操作, 協(xié)議相關(guān)的操作都委派給對(duì)等socket對(duì)象(如SocketChannel對(duì)象委派給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í)間)。

 //打開(kāi)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類(lèi)似,只是可以運(yùn)行在非阻塞模式下

下為一個(gè)通過(guò)ServerSocketChannel構(gòu)建服務(wù)器的簡(jiǎn)單例子,主要體現(xiàn)了非阻塞模式,核心思想與ServerSocket類(lèi)似

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 對(duì)應(yīng) Socket, 模擬TCP協(xié)議;DatagramChannel對(duì)應(yīng)DatagramSocket, 模擬UDP協(xié)議

二者的使用與SeverSocketChannel大同小異,看API即可

工具類(lèi)

文體通道那里我們提到過(guò), 通過(guò)只能操作字節(jié)緩沖區(qū), 編解碼需要應(yīng)用程序自己實(shí)現(xiàn)。如果我們想在通道上直接操作字符,我們就需要使用工具類(lèi)Channels,工具類(lèi)Channels提供了通道與流互相轉(zhuǎn)換、通道轉(zhuǎn)換為閱讀器書(shū)寫(xiě)器的能力,具體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);
//通道  --> 閱讀器書(shū)寫(xiě)器
public static Reader newReader(ReadableByteChannel ch, String csName);
public static Writer newWriter(WritableByteChannel ch, String csName);

通過(guò)將通道轉(zhuǎn)換為閱讀器、書(shū)寫(xiě)器我們就可以直接在通道上操作字符。

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

通道主要分為文件通道和套接字通道。

對(duì)于文件操作:如果是大文件使用通道的文件內(nèi)存映射特性(MappedByteBuffer)來(lái)有利于提升傳輸性能, 否則我更傾向傳統(tǒng)的I/O流模式(字符API);對(duì)于套接字操作, 使用通道可以運(yùn)行在非阻塞模式并且是可選擇的,利于構(gòu)建高性能網(wǎng)絡(luò)應(yīng)用程序。

相關(guān)推薦:java入門(mén)

以上是詳細(xì)介紹Java NIO的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線(xiàn)上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

熱門(mén)話(huà)題

Laravel 教程
1597
29
PHP教程
1488
72