package com.mesopotamia.test; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.util.Scanner; import org.apache.log4j.Logger; /* * 原文學習請加微信訂閱號:it_pupil * **/ public class FileRead { private static Logger logger = Logger.getLogger(FileRead.class); public static void main(String args[]) throws FileNotFoundException{ String path = "C:" + File.separator + "test" + File.separator + "Alice.txt"; readFile3(path); } public static void readFile(String path) throws FileNotFoundException { long start = System.currentTimeMillis();//開始時間 int bufSize = 1024;//1K緩沖區 File fin = new File(path); /* * 通道就是為操作文件而建立的一個連接。(讀寫文件、內存映射等) * 此處的getChannel()可以獲取通道; * 用FileChannel.open(filename)也可以創建一個通道。 * "r"表示只讀。 * * RandomAccessFile是獨立與I/O流家族的類,其父類是Object。 * 該類因為有個指針可以挪動,所以,可以從任意位置開始讀取文件數據。 * **/ FileChannel fcin = new RandomAccessFile(fin, "r").getChannel(); //給字節緩沖區分配大小 ByteBuffer rBuffer = ByteBuffer.allocate(bufSize); String enterStr = "\n"; try { byte[] bs = new byte[bufSize]; String tempString = null; while (fcin.read(rBuffer) != -1) {//每次讀1k到緩沖區 int rSize = rBuffer.position();//記錄緩沖區當前位置 rBuffer.rewind();//位置歸零,標記取消,方便下次循環重新讀入緩沖區。 rBuffer.get(bs);//將緩沖區數據讀到字節數組中 rBuffer.clear();//清除緩沖 /* * 用默認編碼將指定字節數組的數據構造成一個字符串 * bs:指定的字節數組,0:數組起始位置;rSize:數組結束位置 * */ tempString = new String(bs, 0, rSize); int fromIndex = 0;//每次讀的開始位置 int endIndex = 0;//每次讀的結束位置 //按行讀String數據 while ((endIndex = tempString.indexOf(enterStr, fromIndex)) != -1) { String line = tempString.substring(fromIndex, endIndex);//轉換一行 System.out.print(line); fromIndex = endIndex + 1; } } long end = System.currentTimeMillis();//結束時間 System.out.println("傳統IO讀取數據,指定緩沖區大小,總共耗時:"+(end - start)+"ms"); } catch (IOException e) { e.printStackTrace(); } } public static void readFile1(String path) { long start = System.currentTimeMillis();//開始時間 File file = new File(path); if (file.isFile()) { /*使用Reader家族,表示我要讀字符數據了, *使用該家族中的BufferedReader,表示我要建立緩沖區讀字符數據了。 * */ BufferedReader bufferedReader = null; FileReader fileReader = null; try { fileReader = new FileReader(file); //嵌套使用,裝飾者模式,老生常談。裝飾者模式的使用,可以讀前面小磚寫的《從熏肉大餅到裝飾者模式》 bufferedReader = new BufferedReader(fileReader); String line = bufferedReader.readLine(); //一行一行讀 while (line != null) { //按行讀數據 System.out.println(line); line = bufferedReader.readLine(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //最后一定要關閉 try { fileReader.close(); bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } long end = System.currentTimeMillis();//結束時間 System.out.println("傳統IO讀取數據,不指定緩沖區大小,總共耗時:"+(end - start)+"ms"); } } } public static void readFile3(String path) { long start = System.currentTimeMillis();//開始時間 long fileLength = 0; final int BUFFER_SIZE = 0x300000;// 3M的緩沖 File file = new File(path); fileLength = file.length(); try { /*使用FileChannel.map方法直接把整個fileLength大小的文件映射到內存中**/ MappedByteBuffer inputBuffer = new RandomAccessFile(file, "r").getChannel() .map(FileChannel.MapMode.READ_ONLY, 0, fileLength);// 讀取大文件 byte[] dst = new byte[BUFFER_SIZE];// 每次讀出3M的內容 //每3M做一個循環,分段將inputBuffer的數據取出。 for (int offset = 0; offset < fileLength; offset += BUFFER_SIZE) { //防止最后一段不夠3M if (fileLength - offset >= BUFFER_SIZE) { //一個字節一個字節的取出來放到byte[]數組中。 for (int i = 0; i < BUFFER_SIZE; i++) dst[i] = inputBuffer.get(offset + i); } else { for (int i = 0; i < fileLength - offset; i++) dst[i] = inputBuffer.get(offset + i); } // 將得到的3M內容給Scanner,這里的XXX是指Scanner解析的分隔符。 Scanner scan = new Scanner(new ByteArrayInputStream(dst)).useDelimiter("XXX"); //hasNext()所參照的token就是上面的XXX while (scan.hasNext()) { // 這里為對讀取文本解析的方法 System.out.print(scan.next() + "XXX"); } scan.close(); } System.out.println(); long end = System.currentTimeMillis();//結束時間 System.out.println("NIO 內存映射讀大文件,總共耗時:"+(end - start)+"ms"); } catch (Exception e) { e.printStackTrace(); } } }