摘要:一旦聲明不能改變。后數據不能進行讀寫位置,表示緩沖區中正在操作數據的位置。標記,表示記錄當前的位置。緩沖區的限制不能為負,并且不能大于其容量。一通道用于源節點與目標節點的連接。
1.Java NIO 簡介
2.Java NIO 與IO 的主要區別
3.緩沖區(Buffer)和通道(Channel)
4.文件通道(FileChannel)
5.NIO 的非阻塞式網絡通信
?選擇器(Selector)
?SocketChannel、ServerSocketChannel、DatagramChannel
面向流
面向緩沖區
Java NIO(New IO)是從Java 1.4版本開始引入的一個新的IO API,可以替代標準的Java IO API。NIO與原來的IO有同樣的作用和目的,但是使用的方式完全不同,NIO支持面向緩沖區的、基于通道的IO操作。NIO將以更加高效的方式進行文件的讀寫操作。
Java NIO 與IO 的主要區別
import java.nio.ByteBuffer;
import org.junit.Test;
/*
一、緩沖區(Buffer):在 Java NIO 中負責數據的存取。緩沖區就是數組。用于存儲不同數據類型的數據
根據數據類型不同(boolean 除外),提供了相應類型的緩沖區:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
上述緩沖區的管理方式幾乎一致,通過 allocate() 獲取緩沖區
二、緩沖區存取數據的兩個核心方法:
put() : 存入數據到緩沖區中
get() : 獲取緩沖區中的數據
三、緩沖區中的四個核心屬性:
capacity : 容量,表示緩沖區中最大存儲數據的容量。一旦聲明不能改變。
limit : 界限,表示緩沖區中可以操作數據的大小。(limit 后數據不能進行讀寫)
position : 位置,表示緩沖區中正在操作數據的位置。
mark : 標記,表示記錄當前 position 的位置。可以通過 reset() 恢復到 mark 的位置
0 <= mark <= position <= limit <= capacity
四、直接緩沖區與非直接緩沖區:
非直接緩沖區:通過 allocate() 方法分配緩沖區,將緩沖區建立在 JVM 的內存中
直接緩沖區:通過 allocateDirect() 方法分配直接緩沖區,將緩沖區建立在物理內存中。可以提高效率
*/
public class TestBuffer {
@Test public void test3(){ //分配直接緩沖區 ByteBuffer buf = ByteBuffer.allocateDirect(1024); System.out.println(buf.isDirect()); } @Test public void test2(){ String str = "abcde"; ByteBuffer buf = ByteBuffer.allocate(1024); buf.put(str.getBytes()); buf.flip(); byte[] dst = new byte[buf.limit()]; buf.get(dst, 0, 2); System.out.println(new String(dst, 0, 2)); System.out.println(buf.position()); //mark() : 標記 buf.mark(); buf.get(dst, 2, 2); System.out.println(new String(dst, 2, 2)); System.out.println(buf.position()); //reset() : 恢復到 mark 的位置 buf.reset(); System.out.println(buf.position()); //判斷緩沖區中是否還有剩余數據 if(buf.hasRemaining()){ //獲取緩沖區中可以操作的數量 System.out.println(buf.remaining()); } } @Test public void test1(){ String str = "abcde"; //1. 分配一個指定大小的緩沖區 ByteBuffer buf = ByteBuffer.allocate(1024); System.out.println("-----------------allocate()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); //2. 利用 put() 存入數據到緩沖區中 buf.put(str.getBytes()); System.out.println("-----------------put()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); //3. 切換讀取數據模式 buf.flip(); System.out.println("-----------------flip()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); //4. 利用 get() 讀取緩沖區中的數據 byte[] dst = new byte[buf.limit()]; buf.get(dst); System.out.println(new String(dst, 0, dst.length)); System.out.println("-----------------get()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); //5. rewind() : 可重復讀 buf.rewind(); System.out.println("-----------------rewind()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); //6. clear() : 清空緩沖區. 但是緩沖區中的數據依然存在,但是處于“被遺忘”狀態 buf.clear(); System.out.println("-----------------clear()----------------"); System.out.println(buf.position()); System.out.println(buf.limit()); System.out.println(buf.capacity()); System.out.println((char)buf.get()); }
}
1-通道(Channel)與緩沖區(Buffer)
通道和緩沖區
?Java NIO系統的核心在于:通道(Channel)和緩沖區(Buffer)。通道表示打開到IO 設備(例如:文件、套接字)的連接。若需要使用NIO 系統,需要獲取用于連接IO 設備的通道以及用于容納數據的緩沖區。然后操作緩沖區,對數據進行處理。
緩沖區(Buffer)
? 緩沖區(Buffer):一個用于特定基本數據類
型的容器。由java.nio 包定義的,所有緩沖區
都是Buffer 抽象類的子類。
? Java NIO 中的Buffer 主要用于與NIO 通道進行
交互,數據是從通道讀入緩沖區,從緩沖區寫
入通道中的。
緩沖區(Buffer)
Buffer 就像一個數組,可以保存多個相同類型的數據。根
據數據類型不同(boolean 除外) ,有以下Buffer 常用子類:
? ByteBuffer
? CharBuffer
? ShortBuffer
? IntBuffer
? LongBuffer
? FloatBuffer
? DoubleBuffer
上述Buffer 類他們都采用相似的方法進行管理數據,只是各自
管理的數據類型不同而已。都是通過如下方法獲取一個Buffer
對象:
緩沖區的基本屬性
Buffer 中的重要概念:
? 容量(capacity) :表示Buffer 最大數據容量,緩沖區容量不能為負,并且創
建后不能更改。
? 限制(limit):第一個不應該讀取或寫入的數據的索引,即位于limit 后的數據
不可讀寫。緩沖區的限制不能為負,并且不能大于其容量。
? 位置(position):下一個要讀取或寫入的數據的索引。緩沖區的位置不能為
負,并且不能大于其限制
? 標記(mark)與重置(reset):標記是一個索引,通過Buffer 中的mark() 方法
指定Buffer 中一個特定的position,之后可以通過調用reset() 方法恢復到這
個position.
緩沖區的基本屬性
Buffer 的常用方法
緩沖區的數據操作
Buffer 所有子類提供了兩個用于數據操作的方法:get()
與put() 方法
獲取Buffer 中的數據
get() :讀取單個字節
get(byte[] dst):批量讀取多個字節到dst 中
get(int index):讀取指定索引位置的字節(不會移動position)
放入數據到Buffer 中
put(byte b):將給定單個字節寫入緩沖區的當前位置
put(byte[] src):將src 中的字節寫入緩沖區的當前位置
put(int index, byte b):將指定字節寫入緩沖區的索引位置(不會移動position)
直接與非直接緩沖區
字節緩沖區要么是直接的,要么是非直接的。如果為直接字節緩沖區,則Java 虛擬機會盡最大努力直接在
此緩沖區上執行本機I/O 操作。也就是說,在每次調用基礎操作系統的一個本機I/O 操作之前(或之后),
虛擬機都會盡量避免將緩沖區的內容復制到中間緩沖區中(或從中間緩沖區中復制內容)。
直接字節緩沖區可以通過調用此類的allocateDirect() 工廠方法來創建。此方法返回的緩沖區進行分配和取消
分配所需成本通常高于非直接緩沖區。直接緩沖區的內容可以駐留在常規的垃圾回收堆之外,因此,它們對
應用程序的內存需求量造成的影響可能并不明顯。所以,建議將直接緩沖區主要分配給那些易受基礎系統的
本機I/O 操作影響的大型、持久的緩沖區。一般情況下,最好僅在直接緩沖區能在程序性能方面帶來明顯好
處時分配它們。
直接字節緩沖區還可以通過FileChannel 的map() 方法將文件區域直接映射到內存中來創建。該方法返回
MappedByteBuffer 。Java 平臺的實現有助于通過JNI 從本機代碼創建直接字節緩沖區。如果以上這些緩沖區
中的某個緩沖區實例指的是不可訪問的內存區域,則試圖訪問該區域不會更改該緩沖區的內容,并且將會在
訪問期間或稍后的某個時間導致拋出不確定的異常。
字節緩沖區是直接緩沖區還是非直接緩沖區可通過調用其isDirect() 方法來確定。提供此方法是為了能夠在
性能關鍵型代碼中執行顯式緩沖區管理。
非直接緩沖區
直接緩沖區
通道(Channel)
通道(Channel):由java.nio.channels 包定義
的。Channel 表示IO 源與目標打開的連接。
Channel 類似于傳統的“流”。只不過Channel
本身不能直接訪問數據,Channel 只能與
Buffer 進行交互。
通道(Channel)
通道(Channel)
Java 為Channel 接口提供的最主要實現類如下:
?FileChannel:用于讀取、寫入、映射和操作文件的通道。
?DatagramChannel:通過UDP 讀寫網絡中的數據通道。
?SocketChannel:通過TCP 讀寫網絡中的數據。
?ServerSocketChannel:可以監聽新進來的TCP 連接,對每一個新進來
的連接都會創建一個SocketChannel。
獲取通道
獲取通道的一種方式是對支持通道的對象調用
getChannel() 方法。支持通道的類如下:
? FileInputStream
? FileOutputStream
? RandomAccessFile
? DatagramSocket
? Socket
? ServerSocket
獲取通道的其他方式是使用Files 類的靜態方法newByteChannel() 獲
取字節通道。或者通過通道的靜態方法open() 打開并返回指定通道。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.junit.Test; /* * 一、通道(Channel):用于源節點與目標節點的連接。在 Java NIO 中負責緩沖區中數據的傳輸。Channel 本身不存儲數據,因此需要配合緩沖區進行傳輸。 * * 二、通道的主要實現類 * java.nio.channels.Channel 接口: * |--FileChannel * |--SocketChannel * |--ServerSocketChannel * |--DatagramChannel * * 三、獲取通道 * 1. Java 針對支持通道的類提供了 getChannel() 方法 * 本地 IO: * FileInputStream/FileOutputStream * RandomAccessFile * * 網絡IO: * Socket * ServerSocket * DatagramSocket * * 2. 在 JDK 1.7 中的 NIO.2 針對各個通道提供了靜態方法 open() * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具類的 newByteChannel() * * 四、通道之間的數據傳輸 * transferFrom() * transferTo() * * 五、分散(Scatter)與聚集(Gather) * 分散讀取(Scattering Reads):將通道中的數據分散到多個緩沖區中 * 聚集寫入(Gathering Writes):將多個緩沖區中的數據聚集到通道中 * * 六、字符集:Charset * 編碼:字符串 -> 字節數組 * 解碼:字節數組 -> 字符串 * */ public class TestChannel { //字符集 @Test public void test6() throws IOException{ Charset cs1 = Charset.forName("GBK"); //獲取編碼器 CharsetEncoder ce = cs1.newEncoder(); //獲取解碼器 CharsetDecoder cd = cs1.newDecoder(); CharBuffer cBuf = CharBuffer.allocate(1024); cBuf.put("威武!"); cBuf.flip(); //編碼 ByteBuffer bBuf = ce.encode(cBuf); for (int i = 0; i < 12; i++) { System.out.println(bBuf.get()); } //解碼 bBuf.flip(); CharBuffer cBuf2 = cd.decode(bBuf); System.out.println(cBuf2.toString()); System.out.println("------------------------------------------------------"); Charset cs2 = Charset.forName("GBK"); bBuf.flip(); CharBuffer cBuf3 = cs2.decode(bBuf); System.out.println(cBuf3.toString()); } @Test public void test5(){ Mapmap = Charset.availableCharsets(); Set > set = map.entrySet(); for (Entry entry : set) { System.out.println(entry.getKey() + "=" + entry.getValue()); } } //分散和聚集 @Test public void test4() throws IOException{ RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw"); //1. 獲取通道 FileChannel channel1 = raf1.getChannel(); //2. 分配指定大小的緩沖區 ByteBuffer buf1 = ByteBuffer.allocate(100); ByteBuffer buf2 = ByteBuffer.allocate(1024); //3. 分散讀取 ByteBuffer[] bufs = {buf1, buf2}; channel1.read(bufs); for (ByteBuffer byteBuffer : bufs) { byteBuffer.flip(); } System.out.println(new String(bufs[0].array(), 0, bufs[0].limit())); System.out.println("-----------------"); System.out.println(new String(bufs[1].array(), 0, bufs[1].limit())); //4. 聚集寫入 RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw"); FileChannel channel2 = raf2.getChannel(); channel2.write(bufs); } //通道之間的數據傳輸(直接緩沖區) @Test public void test3() throws IOException{ FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); // inChannel.transferTo(0, inChannel.size(), outChannel); outChannel.transferFrom(inChannel, 0, inChannel.size()); inChannel.close(); outChannel.close(); } //使用直接緩沖區完成文件的復制(內存映射文件) @Test public void test2() throws IOException{//2127-1902-1777 long start = System.currentTimeMillis(); FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); //內存映射文件 MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size()); MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); //直接對緩沖區進行數據的讀寫操作 byte[] dst = new byte[inMappedBuf.limit()]; inMappedBuf.get(dst); outMappedBuf.put(dst); inChannel.close(); outChannel.close(); long end = System.currentTimeMillis(); System.out.println("耗費時間為:" + (end - start)); } //利用通道完成文件的復制(非直接緩沖區) @Test public void test1(){//10874-10953 long start = System.currentTimeMillis(); FileInputStream fis = null; FileOutputStream fos = null; //①獲取通道 FileChannel inChannel = null; FileChannel outChannel = null; try { fis = new FileInputStream("d:/1.mkv"); fos = new FileOutputStream("d:/2.mkv"); inChannel = fis.getChannel(); outChannel = fos.getChannel(); //②分配指定大小的緩沖區 ByteBuffer buf = ByteBuffer.allocate(1024); //③將通道中的數據存入緩沖區中 while(inChannel.read(buf) != -1){ buf.flip(); //切換讀取數據的模式 //④將緩沖區中的數據寫入通道中 outChannel.write(buf); buf.clear(); //清空緩沖區 } } catch (IOException e) { e.printStackTrace(); } finally { if(outChannel != null){ try { outChannel.close(); } catch (IOException e) { e.printStackTrace(); } } if(inChannel != null){ try { inChannel.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } long end = System.currentTimeMillis(); System.out.println("耗費時間為:" + (end - start)); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77385.html
摘要:異步可以讓你異步的使用,例如當線程從通道讀取數據到緩沖區時,線程還是可以進行其他事情。當數據被寫入到緩沖區時,線程可以繼續處理它。因此,單個的線程可以監聽多個數據通道。下面是系列文章的目錄概述通道之間的數據傳輸與原文譯者郭蕾校對方騰飛 Java NIO(New IO)是一個可以替代標準Java IO API的IO API(從Java 1.4開始),Java NIO提供了與標準IO不同的...
摘要:線程之間的切換對于操作系統來說是昂貴的。因此,單線程可以監視多個通道中的數據。當方法返回后,線程可以處理這些事件。 一 NIO簡介 Java NIO 是 java 1.4 之后新出的一套IO接口,這里的的新是相對于原有標準的Java IO和Java Networking接口。NIO提供了一種完全不同的操作方式。 NIO中的N可以理解為Non-blocking,不單純是New。 它支持面...
摘要:從通道進行數據寫入創建一個緩沖區,填充數據,并要求通道寫入數據。三之通道主要內容通道介紹通常來說中的所有都是從通道開始的。從中選擇選擇器維護注冊過的通道的集合,并且這種注冊關系都被封裝在當中停止選擇的方法方法和方法。 由于內容比較多,我下面放的一部分是我更新在我的微信公眾號上的鏈接,微信排版比較好看,更加利于閱讀。每一篇文章下面我都把文章的主要內容給列出來了,便于大家學習與回顧。 Ja...
摘要:簡介是由引進的異步由以下幾個核心部分組成和的對比和的區別主要體現在三個方面基于流而基于操作是阻塞的而操作是非阻塞的沒有概念而有概念基于與基于傳統的是面向字節流或字符流的而在中我們拋棄了傳統的流而是引入了和的概念在中我只能從中讀取數據到中或將 簡介 Java NIO 是由 Java 1.4 引進的異步 IO.Java NIO 由以下幾個核心部分組成: Channel Buffer Se...
摘要:學習和掌握技術已經不是一個攻城獅的加分技能,而是一個必備技能。是雙向的,不僅可以讀取數據還能保存數據,程序不能直接讀寫通道,只與緩沖區交互為了讓大家不被高并發與大量連接處理問題所困擾,動力節點推出了高效處理模型應用教程。 大家肯定了解Java IO, 但是對于NIO一般是陌生的,而現在使用到NIO的場景越來越多,很多技術框...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
閱讀 3581·2023-04-26 02:55
閱讀 2849·2021-11-02 14:38
閱讀 4135·2021-10-21 09:39
閱讀 2842·2021-09-27 13:36
閱讀 3943·2021-09-22 15:08
閱讀 2643·2021-09-08 10:42
閱讀 2802·2019-08-29 12:21
閱讀 667·2019-08-29 11:22