91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java NIO是什么

發布時間:2020-10-22 13:41:58 來源:億速云 閱讀:171 作者:小新 欄目:編程語言

這篇文章主要介紹Java NIO是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

Java NIO主要需要理解緩沖區、通道、選擇器三個核心概念,作為對Java I/O的補充, 以提升大批量數據傳輸的效率。

學習NIO之前最好能有基礎的網絡編程知識

Java I/O流

Java 網絡編程

Java NIO:緩沖區

通道(Channel)作為NIO的三大核心概念之一(緩沖區、通道、選擇器),用于在字節緩沖區與位于通道另一側的實體(文件或者套接字)之間有效的傳輸數據(核心是傳輸數據)

NIO編程的一般模式是:把數據填充到發送字節緩沖區 --> 通過通道發送到通道對端文件或者套接字

通道基礎

使用Channel的目的是進行數據傳輸,使用前需要打開通道、使用后需要關閉通道

打開通道

我們知道I/O有兩大類:File IO和 Stream I/O,其對應到通道也就有文件通道(FileChannel)和套接字通道(SocketChannel、ServerSocketChannel、DatagramChannel)兩種

對于套接字通道,使用靜態工廠方法打開

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

對于文件通道只能通過對一個RandomAccessFile、FileInputStream、FileOutputStream對象調用getChannel()方法獲取

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

使用通道進行數據傳輸

下段代碼首先將要寫入的數據放到ByteBuffer中, 然后打開文件通道,把緩沖區中的數據放到文件通道。

//準備數據并放入字節緩沖區
ByteBuffer bf = ByteBuffer.allocate(1024);
bf.put("i am cool".getBytes());
bf.flip();
//打開文件通道
FileOutputStream out = new FileOutputStream("/tmp/a.txt");
FileChannel fc = out.getChannel();
//數據傳輸
fc.write(bf);
//關閉通道
fc.close();

關閉通道

如同Socket、FileInputStream等對象使用完畢之后需要關閉一樣, 通道使用之后也需要關閉。一個打開的通道代表與一個特定I/O服務的特定連接并封裝該連接的狀態,通道關閉時連接丟失,不再連接任何東西。

阻塞 & 非阻塞模式

通道有阻塞和非阻塞兩種運行模式,非阻塞模式的通道永遠不會休眠,請求的操作要么立即完成,要么返回一個結果表明未進行任何操作(具體看Socket通道處的描述)。只有面向流的通道可使用非阻塞模式

文件通道

文件通道用于對文件進行訪問, 通過對一個RandomAccessFile、FileInputStream、FileOutputStream對象調用getChannel()方法獲取。調用getChannel方法返回一個連接到相同文件的FileChannel對象,該FileChannel對象具有與file對象相同的訪問權限。

文件訪問

使用文件通道的目的還是對文件進行讀寫操作,通道的讀寫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中讀取數據,直到文件尾
ByteBuffer bb = ByteBuffer.allocate(1024);
while (fc.read(bb) != -1) {
;
}
//翻轉(讀之前需要先進行翻轉)
bb.flip();
StringBuilder builder = new StringBuilder();
//把每一個字節轉為字符(ascii編碼)
while (bb.hasRemaining()) {
builder.append((char) bb.get());
}
System.out.println(builder.toString());

上面這個demo有個問題:我們只能讀取字節, 然后由應用程序去解碼,這個問題我們可以通過工具類Channels將通道包裝成Reader和Writer來解決;當然我們也可以直接使用Java I/O流模式的Reader和Writer操作字符

文件通道位置與文件空洞

文件通道位置(position)就是普通文件的位置, position的值決定了文件中哪個位置的數據接下來將被讀或者寫

讀取超出文件尾部位置的數據會返回-1(文件EOF)

往一個超出文件尾部的位置寫入數據會造成文件空洞:比如一個文件現在有10個字節, 但是此時往position=20 處寫入數據就會造成10~20之間的位置是沒有數據的,這就是文件空洞

force操作

force操作強制通道將全部修改立即應用到磁盤文件(防止系統宕機導致修改丟失)

public abstract void force(boolean metaData) throws IOException;

內存文件映射

FileChannel提供了一個map()方法,該方法可以在一個打開的文件和特殊類型的ByteBuffer(MappedByteBuffer)之間建立一個虛擬內存映射。

因為map方法返回的MappedByteBuffer對象是直接緩沖區,所以通過MappedByteBuffer來操作文件非常高效(尤其是大量數據傳輸的情況)

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模式下寫操作寫的是一個臨時緩沖區,不會真正去寫文件。(寫時拷貝思想)

Socket通道

Socket 通道可以運行在非阻塞模式且是可選擇的,這兩點使得對于網絡編程我們不再需要為每個Socket連接創建一個線程,而是使用一個線程即可管理成百上千的Socket連接。

所有的Socket通道在實例化的時候都會創建一個對象的Socket對象, Socket通道并不負責協議相關的操作, 協議相關的操作都委派給對等socket對象(如SocketChannel對象委派給Socket對象)

非阻塞模式

相較于傳統Java Socket的阻塞模式,SocketChannel提供了非阻塞模式,以構建高性能的網絡應用程序

非阻塞模式下,幾乎所有的操作都是立刻返回的。比如下面的SocketChannel運行在非阻塞模式下,connect操作會立即返回,如果success為true代表連接已經建立成功了, 如果success為false, 代表連接還在建立中(tcp連接需要一些時間)。

 //打開Socket通道
 SocketChannel ch = SocketChannel.open();
 //非阻塞模式
 ch.configureBlocking(false);
 //連接服務器 
 boolean success = ch.connect(InetSocketAddress.createUnresolved("127.0.0.1", 7001));
 //輪訓連接狀態, 如果連接還未建立就可以做一些別的工作
 while (!ch.finishConnect()){
    //dosomething else
 }
 //連接建立, 做正事
 //do something;

ServerSocketChannel

ServerSocketChannel與ServerSocket類似,只是可以運行在非阻塞模式下

下為一個通過ServerSocketChannel構建服務器的簡單例子,主要體現了非阻塞模式,核心思想與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 對應 Socket, 模擬TCP協議;DatagramChannel對應DatagramSocket, 模擬UDP協議

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

工具類

文體通道那里我們提到過, 通過只能操作字節緩沖區, 編解碼需要應用程序自己實現。如果我們想在通道上直接操作字符,我們就需要使用工具類Channels,工具類Channels提供了通道與流互相轉換、通道轉換為閱讀器書寫器的能力,具體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);

通過將通道轉換為閱讀器、書寫器我們就可以直接在通道上操作字符。

    RandomAccessFile f = new RandomAccessFile("/tmp/a.txt", "r");
  FileChannel fc = f.getChannel();
  //通道轉換為閱讀器,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]);
  }

總結

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

對于文件操作:如果是大文件使用通道的文件內存映射特性(MappedByteBuffer)來有利于提升傳輸性能, 否則我更傾向傳統的I/O流模式(字符API);對于套接字操作, 使用通道可以運行在非阻塞模式并且是可選擇的,利于構建高性能網絡應用程序。

以上是Java NIO是什么的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

淮安市| 临清市| 安西县| 古田县| 林芝县| 平凉市| 大方县| 山阳县| 大名县| 囊谦县| 武定县| 隆安县| 南乐县| 宿松县| 长海县| 印江| 红原县| 西峡县| 和平区| 宁国市| 巫山县| 吉隆县| 盐边县| 广南县| 新津县| 淮阳县| 章丘市| 漳平市| 都兰县| 梁平县| 象山县| 金昌市| 河曲县| 威远县| 卢湾区| 兴安盟| 左云县| 都匀市| 保德县| 贵南县| 滦南县|