FileChannel 是一個連接到文件的通道,使用 FileChannel 可以從文件讀數據,也可以向文件中寫入數據。Java NIO 的 FileChannel 是標準 Java IO 讀寫文件的替代方案。
FileChannel 不能設置爲非阻塞的模式,也就是說 FileChannel 總是阻塞的。
1、開啓 FileChannel
在使用 FileChannel 之前必須先開啓。但是不能直接開啓一個 FileChannel,需要通過一個 InputStream、OutputStream 或者 RandomAccessFile 獲取它。下面是一個使用 RandomAccessFile 獲取一個 FileChannel 對象的示例:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
2、從 FileChannel 中讀取數據
從 FileChannel 中讀取數據可以通過調用其中的一個 read() 方法完成,下面是一個示例:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);//將 Channel 中的數據讀入到 Buffer
首先要分配一個 Buffer,然後調用 FileChannel 的 read() 方法。從 FileChannel 中讀取數據就是將該 FileChannel 中的數據讀取到分配的 Buffer 中。read() 方法的返回值就是向 Buffer 中讀取了多少個字節,如果返回 -1,則說明該文件已經被讀取完了。
3、向 FileChannel 中寫入數據
向 FileChannel 中寫入數據需要調用 FileChannel 的 write() 方法,將 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);// 將 Buffer 中的數據寫入到 Channel 中
}
注意:要將 FileChannel.write() 方法的調用放在一個 while 循環中,因爲無法保證 write() 方法一次能將 Buffer 中的多少字節寫入到 FileChannel 中,因此我們需要重複的調用 write() 直到 Buffer 中沒有字節可以寫。
4、關閉 FileChannel
FileChannel 使用完之後必須關閉,示例如下:
channel.close();
5、FileChannel 的 position
如果想在 FileChannel 的某一個指定位置讀寫數據,可以通過調用 FileChannel 的 position() 方法來獲取當前的 position 值,也可以調用 FileChannel 的 position(long pos) 方法設置 position 的值,示例如下:
long pos channel.position();
channel.position(pos +123);
如果設置的 position 值超出了 File 文件的最後位置,在讀取該 Channel 時就會返回 -1 ,即返回“讀取到文件的末尾”的標識。但此時若向 Channel 中寫入數據,該 Channel 連接的 File 會被“擴張”到這個設置的 position 值的位置,然後將數據寫入到這個 File 中,這會導致該 File 帶有“空洞”,存儲在磁盤上的這個物理文件就會不連續。
6、FileChannel 的 size
FileChannel 的 size() 方法會返回這個 FileChannel 連接的 File 文件的大小,示例如下:
long fileSize = channel.size();
7、FileChannel 的 截斷
可以調用 FileChannel.truncate() 方法截斷一個 File。截斷時需要指定一個長度,示例如下:
channel.truncate(1024);
本示例將文件長度截斷爲1024個字節。
8、FileChannel 的強制
FileChannel.force() 方法會將 Channel 中所有未寫入磁盤的數據強制寫入磁盤。由於性能的原因操作系統可能會將一些數據緩存在內存中,因此無法確切地保證數據被寫入到了磁盤,除非調用了 force() 方法。
force() 方法採用布爾值作爲參數,指明是否同時應刷新文件的元數據信息(比如權限等)。
下面是一個同時刷新數據和元數據的示例:
channel.force(true);