在執行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();
}
}
} |