三種實現
1. 傳統 IO (FileInputStream + ByteArrayOutputStream)
public static byte[] toByteArray(String filename) throws IOException {
try (FileInputStream fis = new FileInputStream(filename);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) baos.write(buf, 0, len);
return baos.toByteArray();
}
}
2. NIO (FileChannel + ByteBuffer)
public static byte[] toByteArray2(String filename) throws IOException {
try (FileInputStream fis = new FileInputStream(filename);
FileChannel channel = fis.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate((int) channel.size());
while (channel.read(buffer) > 0) ; // 循環讀滿
return buffer.array();
}
}
3. 內存映射 (MappedByteBuffer) — 大文件最快
public static byte[] toByteArray3(String filename) throws IOException {
try (FileChannel fc = new RandomAccessFile(filename, "r").getChannel()) {
MappedByteBuffer mb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
mb.load(); // 預加載進內存
byte[] dst = new byte[(int) fc.size()];
if (mb.remaining() > 0) mb.get(dst);
return dst;
}
}
性能測試 (100MB 文件,SSD,JDK 11)
| 方式 | 耗時 | 適用場景 |
| 傳統 IO | ~180 ms | 小文件、兼容性最好 |
| NIO ByteBuffer | ~120 ms | 中等文件、非阻塞網絡 |
| MappedByteBuffer | ~40 ms | 大文件(>100MB)、頻繁隨機讀取 |
選型建議
- < 10MB:傳統 IO 簡單可靠。
- 10MB - 100MB:NIO ByteBuffer 平衡。
- > 100MB 或需隨機讀取:MappedByteBuffer 零拷貝、OS 頁面緩存加速。
- Java 9+:
Files.readAllBytes(Path) 內部自動選擇最優策略。
注意事項
- MappedByteBuffer 映射大小受進程虛擬內存限制(32位 JVM 受限)。
- 內存映射文件變更需
force() 刷盤,讀取場景無需關心。
- 所有流/通道務必關閉,建議 try-with-resources。