搜尋
首頁JavaJava入門詳細介紹Java NIO
詳細介紹Java NIOOct 21, 2020 pm 04:35 PM
java nio

詳細介紹Java NIO

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

(推薦教學:java課程

學習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入门

以上是詳細介紹Java NIO的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。