詳解NIO中FileChannel文件流的簡單使用
前言
在文章NIO 下的 ByteBuffer簡單學習 中, 我們有寫過一個簡單的文件讀取案例, 在案例中有使用到 Buffer 和 Channel, 關於 Buffer 的簡單使用可以看下面兩篇文章
- NIO 下的 ByteBuffer簡單學習
- 最簡單的 NIO 粘包解析與分析
關於 Channel 主要分為以下幾種, 本篇文章是對 FileChannel 的講解:
- FileChannel: 文件通道, 主要用於對文件的讀寫
- DatagramChannel: 數據包通道, 可以發送和接受 UPD 的數據包
- SocketChannel: 套接字通過, 接收 TCP 數據包的讀寫
- ServerSocketChannel: 服務器套接字通道, 監聽新進來的 TCP 連接, 為每一個新連接都創建一個 SocketChannel
FileChannel
註意: FileChannel 隻能工作在阻塞模式下
新建
FileChannel 是一個抽象類, 所以不能直接創建對象
public abstract class FileChannel extends AbstractInterruptibleChannel implements SeekableByteChannel, GatheringByteChannel,ScatteringByteChannel { /** * Initializes a new instance of this class. * */ protected FileChannel(){}
創建一個 FileChannel 有以下三種方式:
- 創建一個 FileInputStream 對象, 但是該對象獲取到的 Channel 隻能讀取
- 創建一個 FileOutputStream 對象, 但是該對象獲取到的 Channel 隻能寫入
- 創建一個 RandomAccessFile 對象, 該對象能否讀寫是根據構造 RandomAccessFile 時設置的讀寫模式設定的
註意: Channel 使用之後必須關閉
不主動 close 並且 未觸發gc , 那麼 連接 和 句柄 將被 一直占用, 如果此時使用的是連接池方式, 將造成連接池中的連接不能及時的被回收問題
在調用 FileInputStream 、 FileOutputStream 和 RandomAccessFile 的 close 方法會間接調用 Channel 的 close 方法
實現文件的讀寫
通過以下代碼可以簡單的通過 FileInputStream 和 FileOutputStream 來實現對文件的讀寫
public static void main(String[] args) { try( FileChannel inputChannel = new FileInputStream( name: "test1.txt").getChannel(); FileChannel outputChannel = new FileOutputStream( name: "test2.txt").getChannel() ){ // inputChannel 流讀取到的內容通過 outputChannel 傳輸到指定的地址 inputChannel.transferTo( position: 0,inputChannel.size(),outputChannel); }catch (Exception e){ e.printstackTrace(); } }
但是這裡有個問題, FileChannel 的 transferTo 隻能傳輸 2G 以內的數據, 超過 2G 就傳輸不瞭瞭,
下面是 FileChannel 的 tarnsferTo 方法, 可以看到他是存在返回值的, 這個返回值就代表著還剩下多少字節的內容沒有進行傳輸, 所以我們可以使用一個 for 循環來對當前的代碼進行改進
改進後的代碼如下所示
public static void main(String[] args) { try( FileChannel inputChannel = new FileInputStream( name: "test1.txt").getChannel(); FileChannel outputChannel = new FileOutputStream( name: "test2.txt").getChannel() ){ //獲取到 輸入流 的大小 long size = inputChannel.size(); // res 代表剩餘多少字節沒有進行傳輸 for (long res = size;res > 0; ){ //將 inputChannel 流讀取到的內容通過 outputChannel 傳輸到指定的地址 // 效率高,底層會利用作系統的 零拷貝 進行優化,但是一次隻能傳輸 2G 的數據 // 該方法返回值為 剩餘未傳輸的 字節數 res = inputChannel.transferTo( position: 0,inputChannel.size(), outputChannel); } }catch (Exception e){ e.printstackTrace(); } }
本篇文章所有代碼
public static void main(String[] args) { try( FileChannel inputChannel = new FileInputStream("test1.txt").getChannel(); FileChannel outputChannel = new FileOutputStream("test2.txt").getChannel() ){ // 獲取到 輸入流 的大小 long size = inputChannel.size(); // res 代表剩餘多少字節沒有進行傳輸 for (long res = size; res > 0; ){ // 將 inputChannel 流讀取到的內容通過 outputChannel 傳輸到指定的地址 // 效率高, 底層會利用操作系統的 零拷貝 進行優化, 但是一次隻能傳輸 2G 的數據 // 該方法返回值為 剩餘未傳輸的 字節數 res = inputChannel.transferTo(0, inputChannel.size(), outputChannel); } }catch (Exception e){ e.printStackTrace(); } }
到此這篇關於詳解NIO中FileChannel文件流的簡單使用的文章就介紹到這瞭,更多相關FileChannel使用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳細總結Java堆棧內存、堆外內存、零拷貝淺析與代碼實現
- Java NIO Buffer實現原理詳解
- Java NIO 中Buffer 緩沖區解析
- Java Buffer緩沖區(NIO)
- Java FileInputStream與FileOutputStream使用詳解