在執行IO時,Java的InputStream被廣泛使用,比如DataInputStream.readInt等等。事實上,這些高度封裝的介面奇慢無比。我有一個項目啟動時需要讀取90MB左右的詞典檔案,用DataInputStream耗時3秒以上,換用java.nio包直接操作記憶體位元組,可以加速到300ms左右,整整提速10倍!當然,前提是你熟悉位元運算。
java.nio中提供了兩類 FileChannel 和 ByteBuffer來將檔案對應到記憶體,其中FileChannel表示檔案通道,ByteBuffer是一個緩衝區。
具體步驟
①從FileInputStream、FileOutputStream以及RandomAccessFile對象擷取檔案通道
②將檔案記憶體映射到ByteBuffer
③通過byteBuffer.array()介面得到一個byte數組
④直接操作位元組
範例程式碼
代碼如下 |
複製代碼 |
FileInputStream fis = new FileInputStream(path); // 1.從FileInputStream對象擷取檔案通道FileChannel FileChannel channel = fis.getChannel(); int fileSize = (int) channel.size(); // 2.從通道讀取檔案內容 ByteBuffer byteBuffer = ByteBuffer.allocate(fileSize); // channel.read(ByteBuffer) 方法就類似於 inputstream.read(byte) // 每次read都將讀取 allocate 個位元組到ByteBuffer channel.read(byteBuffer); // 注意先調用flip方法反轉Buffer,再從Buffer讀取資料 byteBuffer.flip(); // 可以將當前Buffer包含的位元組數組全部讀取出來 byte[] bytes = byteBuffer.array(); byteBuffer.clear(); // 關閉通道和檔案流 channel.close(); fis.close(); int index = 0; size = Utility.bytesHighFirstToInt(bytes, index); index += 4;
|
其中,如果你當初使用了DataOutputStream.writeInt來儲存檔案的話,那麼在讀取的時候就要注意了。writeInt寫入四個位元組,其中高位在前,低位在後,所以將byte數組轉為int的時候需要倒過來轉換:
代碼如下 |
複製代碼 |
/** * 位元組數組和整型的轉換,高位在前,適用於讀取writeInt的資料 * * @param bytes 位元組數組 * @return 整型 */ public static int bytesHighFirstToInt(byte[] bytes, int start) { int num = bytes[start + 3] & 0xFF; num |= ((bytes[start + 2] << 8) & 0xFF00); num |= ((bytes[start + 1] << 16) & 0xFF0000); num |= ((bytes[start] << 24) & 0xFF000000); return num; } |
改變buffer的大小也可以起到使用
代碼如下 |
複製代碼 |
public static void copy1(File src, File dest) throws Exception { FileInputStream fileInputStream = null; FileOutputStream fileOutputStream = null; try { fileInputStream = new FileInputStream(src); fileOutputStream = new FileOutputStream(dest); byte[] buffer = new byte[8096]; int length = -1; while((length = fileInputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, length);//一次性將緩衝區的所有資料都寫出去 fileOutputStream.flush(); } } finally { if(fileInputStream != null) { fileInputStream.close(); } if(fileOutputStream != null) { fileOutputStream.close(); } } } |