2025-02-17

Java NIO 入門(三)從理論到實踐:使用NIO讀寫
guibin.beijing@gmail.com

概述
讀和寫是最基礎的IO處理。從Channel中讀是非常簡單的,我們隻要創建一個Buffer,然後要求Channel往Buffer中讀數據。寫也很簡單,也需要創建一個Buffer,把要寫的數據填充到Buffer中,然後要求Channel把Buffer中的數據寫出去。

在這節中,我們學習使用JAVA程序來讀寫數據,順便瀏覽一下NIO的主要組件(Buffer,Channel以及相關的方法)並且看看他們在讀寫數據時如何交互,在後面的章節中我們將依次查看每個組件的細節。

從文件中讀數據
在第一個練習中,我們首先從文件中讀取一些數據。如果使用老的IO,隻需要簡單的創建FileInputStream,然後從中讀取數據。在NIO中,事情變得有些不同瞭,首先需要從FileInputStream中獲取Channel對象,然後使用這個Channel去讀文件。

在NIO系統中任何時刻執行一個讀操作時,都要從Channel中讀,但不是直接從Channel中讀。由於所有的數據都需要通過Buffer承載,所以需首先從Channel中把數據讀進Buffer。

因此,從文件中讀數據一共有三步:
從FileInputStream中獲取Channel
創建Buffer
從Channel中把數據讀入Buffer

下面我們仔細看看具體時如何工作的。

三步簡單的工作
第一步獲取Channel。從FileInputStream中獲取Channel。
Java代碼 
FileInputStream fin = new FileInputStream( "readandshow.txt" );  
FileChannel fc = fin.getChannel(); 

第二步創建Buffer
Java代碼 
ByteBuffer buffer = ByteBuffer.allocate( 1024 ); 

最後一步,將文件內容通過Channel讀入Buffer中
Java代碼 
fc.read( buffer ); 

你一定發現,在這裡,並沒有告訴Channel把多少內容讀進Buffer。在每個Buffer中都有一套完整的內部計數系統來跟蹤已經讀瞭多少數據瞭,Buffer中還剩多少空間。關於Buffer的計數系統在隨後的“Buffer內部原理”中講解。

寫文件
使用NIO寫文件和讀文件非常類似。我們還是從FileOutputStream中獲取Channel。
Java代碼 
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" ); 
FileChannel fc = fout.getChannel(); 

下一步還是創建Buffer並且把數據放到Buffer中。在這種情況下數據將從一個叫做message的數組中取出,這個數組中包含瞭字符串ASCII碼的字節。(The buffer.flip() 和 buffer.put()在後面講解)
Java代碼 
ByteBuffer buffer = ByteBuffer.allocate( 1024 ); 
for (int i=0; i<message.length; ++i) {  
  buffer.put( message[i] ); 
}  
buffer.flip(); 

最後一步就是把Buffer寫出去。
Java代碼 
fc.write( buffer ); 


再次註意,我們沒有必要告訴Channel總共要寫多少數據,Buffer的內部計數系統會跟蹤已經寫瞭多少數據瞭,還剩多少空間可以使用。

邊讀邊寫
下面看看當我們把讀和寫結合起來會發生什麼。這個練習程序的名稱叫CopyFile.java,用來從一個文件拷貝全部數據到另一個文件。Copy.java包含瞭三個基本的操作:
首先創建Buffer
然後從源文件把數據讀入Buffer
最後把Buffer寫入目的文件

程序重復的進行讀寫、讀寫,直到文件讀完。

CopyFile程序能夠看到如何檢查程序的狀態,以及如何使用clear(),flip()方法重置Buffer,如何讀數據從一個Channel到另一個Channel。

運行CopyFile例子
因為Buffer跟蹤瞭自己的內部數據,因此CopyFile程序的內部循環非常簡單,如下:
Java代碼 
fcin.read( buffer );  
fcout.write( buffer ); 

首先數據從輸入Channel中讀入Buffer,然後把數據寫出到輸出Channel中。因為輸入和輸出分別對應於兩個文件,因此是兩個Channel。

檢查讀文件的狀態
下一步,當我們在拷貝時需要檢查讀文件的狀態。當沒有數據可讀時即執行完畢,這個狀態可以通過read()方法返回-1來判斷,如下:
Java代碼 
int r = fcin.read( buffer ); 
if (r==-1) {  
  break; 


重置Buffer
最後,在從Channel將數據讀入Buffer前調用clear()方法,相似的,在將Buffer寫入輸出Channel之前調用flip()方法。
Java代碼 
buffer.clear();  
int r = fcin.read( buffer ); 
 
if (r==-1) {  
  break; 

 
buffer.flip();  
fcout.write( buffer ); 


clear()方法重置瞭Buffer,使其準備好能夠將讀入的數據放入Buffer中。flip()方法使得Buffer準備好把Buffer中的數據寫入Channel。

作者“guibin”
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *