1. 程式人生 > >Java NIO系列教程(七) FileChannel

Java NIO系列教程(七) FileChannel

原文連結     作者:Jakob Jenkov     譯者:周泰      校對:丁一

Java NIO中的FileChannel是一個連線到檔案的通道。可以通過檔案通道讀寫檔案。

FileChannel無法設定為非阻塞模式,它總是執行在阻塞模式下。

開啟FileChannel

在使用FileChannel之前,必須先開啟它。但是,我們無法直接開啟一個FileChannel,需要通過使用一個InputStream、OutputStream或RandomAccessFile來獲取一個FileChannel例項。下面是通過RandomAccessFile開啟FileChannel的示例:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

從FileChannel讀取資料

呼叫多個read()方法之一從FileChannel中讀取資料。如:

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

首先,分配一個Buffer。從FileChannel中讀取的資料將被讀到Buffer中。

然後,呼叫FileChannel.read()方法。該方法將資料從FileChannel讀取到Buffer中。read()方法返回的int值表示了有多少位元組被讀到了Buffer中。如果返回-1,表示到了檔案末尾。

向FileChannel寫資料

使用FileChannel.write()方法向FileChannel寫資料,該方法的引數是一個Buffer。如:

String newData = "New String to write to file..." + System.currentTimeMillis();

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {
	channel.write(buf);
}

注意FileChannel.write()是在while迴圈中呼叫的。因為無法保證write()方法一次能向FileChannel寫入多少位元組,因此需要重複呼叫write()方法,直到Buffer中已經沒有尚未寫入通道的位元組。

關閉FileChannel

用完FileChannel後必須將其關閉。如:

channel.close();

FileChannel的position方法

有時可能需要在FileChannel的某個特定位置進行資料的讀/寫操作。可以通過呼叫position()方法獲取FileChannel的當前位置。

也可以通過呼叫position(long pos)方法設定FileChannel的當前位置。

這裡有兩個例子:

long pos = channel.position();
channel.position(pos +123);

如果將位置設定在檔案結束符之後,然後試圖從檔案通道中讀取資料,讀方法將返回-1 —— 檔案結束標誌。

如果將位置設定在檔案結束符之後,然後向通道中寫資料,檔案將撐大到當前位置並寫入資料。這可能導致“檔案空洞”,磁碟上物理檔案中寫入的資料間有空隙。

FileChannel的size方法

FileChannel例項的size()方法將返回該例項所關聯檔案的大小。如:

long fileSize = channel.size();

FileChannel的truncate方法

可以使用FileChannel.truncate()方法擷取一個檔案。擷取檔案時,檔案將中指定長度後面的部分將被刪除。如:

channel.truncate(1024);

這個例子擷取檔案的前1024個位元組。

FileChannel的force方法

FileChannel.force()方法將通道里尚未寫入磁碟的資料強制寫到磁碟上。出於效能方面的考慮,作業系統會將資料快取在記憶體中,所以無法保證寫入到FileChannel裡的資料一定會即時寫到磁碟上。要保證這一點,需要呼叫force()方法。

force()方法有一個boolean型別的引數,指明是否同時將檔案元資料(許可權資訊等)寫到磁碟上。

下面的例子同時將檔案資料和元資料強制寫到磁碟上:

channel.force(true);