FileChannel是什么
它是用於讀取、寫入、映射和操作文件的通道。除了熟悉的字節通道讀取,寫入和關閉操作之外,此類還定義了以下特定於文件的操作:
-
可以以不影響通道當前位置的方式在文件中的絕對位置讀取或寫入字節。
-
文件的區域可以直接映射到內存中。 對於大文件,這通常比調用通常的讀取或寫入方法要有效得多。
-
對文件所做的更新可能會被強制發送到基礎存儲設備,以確保在系統崩潰時不會丟失數據。
-
字節可以從文件傳輸到其他通道,反之亦然,可以通過許多操作系統進行優化,將字節快速傳輸到文件系統緩存或直接從文件系統緩存傳輸。
-
文件的區域可能被鎖定,以防止其他程序訪問。
FileChannel配合着ByteBuffer,將讀寫的數據緩存到內存中,然后以批量/緩存的方式read/write,省去了非批量操作時的重復中間操作,操縱大文件時可以顯著提高效率。ByteBuffer可以使用直接內存(系統內存)(allocateDirect),使用后無需jvm回收。
總結一下,按照字節讀取,對大文件讀取效率更高,無法設置為非阻塞模式,它總是運行在阻塞模式下。
但有時候我們要按照行讀取文件,而FileChannel只能按照字節讀取,所以這里需要對換行進行判斷一下,在這里我對其進行了實現,供大家參考。
實現
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class test1 {
public static void readLineByChannel(String path) throws IOException {
long lineNumber = 0;
FileInputStream fileIn = new FileInputStream(path);
FileChannel fileChannel = fileIn.getChannel();
// 開始按行讀取
int bufferSize = 1024 * 1024; // 每一塊的大小
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
byte b;
while(fileChannel.read(buffer) > 0)
{
buffer.flip();
for (int i = 0; i < buffer.limit(); i++)
{
b = buffer.get();
if(b==10){ // 如果遇到換行
lineNumber++;
}
}
buffer.clear(); // 清空buffer
}
fileChannel.close();
System.out.println(lineNumber);
}
public static void readLineByBufferedReader(String path) throws IOException {
long lineNumber = 0;
FileInputStream inputStream = new FileInputStream(path);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line=bufferedReader.readLine()) != null)
{
lineNumber++;
}
inputStream.close();
bufferedReader.close();
System.out.println(lineNumber);
}
public static void main(String[] args) throws IOException {
String path = "大文件";
long startTime = System.currentTimeMillis();
readLineByChannel(path);
System.out.println("readLineByChannel耗時:" + (System.currentTimeMillis() - startTime));
startTime = System.currentTimeMillis();
readLineByBufferedReader(path);
System.out.println("readLineByBufferedReader耗時:" + (System.currentTimeMillis() - startTime));
}
}
使用FileChannel和BufferedReader分別的對大文件進行讀取,並且計算有多少行。
//第一次測試:
169860474
readLineByChannel耗時:27310
169860474
readLineByBufferedReader耗時:24944
//第二次測試
169860474
readLineByChannel耗時:28677
169860474
readLineByBufferedReader耗時:21229
測試文件12GB,可以看出文件有1億6千多萬行,實際測試下來兩者差距不大,甚至BufferedReader還快點。
