# Java中幾種文件讀寫的性能對比
準備:
```
static byte[] data = "123456789\n".getBytes();
static String path = "/root/testfileio/out.txt";
```
查看系統臟頁及文件被緩存大小:
```
ll -h out.txt && /home/golang/go/bin/pcstat out.txt && cat /proc/vmstat | egrep "dirty|writeback"
```
## 一、使用最傳統的stream
~~~
public static void testBasicFileIO() throws Exception {
File file = new File(path);
FileOutputStream out = new FileOutputStream(file);
while (true) {
out.write(data);
}
}
~~~
其中data為10個字節大小的字節數組,在while循環中不斷的將其寫入文件中。查看輸出文件的增長大小,會發現增長的還是比較緩慢的。同時所有的內容也會被pageCache所緩存(緩沖的限制可以查看dirty_ratio參數。)
:-: 
即是暫停了程序,會發現該文件仍然有緩存在pageCache中,如果這個時候突然斷電,可能就會導致數據丟失,因為有可能沒有被持久化到磁盤中。
## 二、使用buffer + stream
~~~
public static void testBufferedFileIO() throws Exception {
File file = new File(path);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
while (true) {
out.write(data);
}
}
~~~
源碼:
~~~
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
// 先放到本地的buffer中
buf[count++] = (byte)b;
}
~~~
可以發現使用buffer之后其寫入的速度比沒有使用buffer就會快很多。其原因是Buffer流會在用戶空間中準備一個8KB大小的字節數組作為緩沖區,該數組滿了之后才會發生一次調用系統,一次性的寫入8KB的內容。這樣就大大的減少了系統調用的次數,因此要比沒有使用Buffer的快很多。
同時在查看文件的緩存大小的時候會發現系統有明顯的卡頓現象,這是因為當在臟頁的數據超過一定比例之后需要暫停進行臟頁的落盤。
:-: 
## 三、使用mmap
~~~
public static void testRandomAccessFileWrite() throws Exception {
RandomAccessFile raf = new RandomAccessFile(path, "rw");
FileChannel rafchannel = raf.getChannel();
//mmap 使得jvm堆和pageCache有一塊映射空間
MappedByteBuffer map = rafchannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096 * 1024 * 250); // 1000M的pageCache大小
while (true) {
map.put(data); //不是系統調用 但是數據會到達 內核的pagecache
}
}
~~~
可以看到快1G的pageCache寫入幾乎是一瞬間的事情。使用mmap會直接在pageCache中開辟一塊空間,作為映射(思考一些虛擬內存的地址轉化),不會發生系統調用。
使用拓撲圖總結:
:-: 
- 第一章 Java基礎
- ThreadLocal
- Java異常體系
- Java集合框架
- List接口及其實現類
- Queue接口及其實現類
- Set接口及其實現類
- Map接口及其實現類
- JDK1.8新特性
- Lambda表達式
- 常用函數式接口
- stream流
- 面試
- 第二章 Java虛擬機
- 第一節、運行時數據區
- 第二節、垃圾回收
- 第三節、類加載機制
- 第四節、類文件與字節碼指令
- 第五節、語法糖
- 第六節、運行期優化
- 面試常見問題
- 第三章 并發編程
- 第一節、Java中的線程
- 第二節、Java中的鎖
- 第三節、線程池
- 第四節、并發工具類
- AQS
- 第四章 網絡編程
- WebSocket協議
- Netty
- Netty入門
- Netty-自定義協議
- 面試題
- IO
- 網絡IO模型
- 第五章 操作系統
- IO
- 文件系統的相關概念
- Java幾種文件讀寫方式性能對比
- Socket
- 內存管理
- 進程、線程、協程
- IO模型的演化過程
- 第六章 計算機網絡
- 第七章 消息隊列
- RabbitMQ
- 第八章 開發框架
- Spring
- Spring事務
- Spring MVC
- Spring Boot
- Mybatis
- Mybatis-Plus
- Shiro
- 第九章 數據庫
- Mysql
- Mysql中的索引
- Mysql中的鎖
- 面試常見問題
- Mysql中的日志
- InnoDB存儲引擎
- 事務
- Redis
- redis的數據類型
- redis數據結構
- Redis主從復制
- 哨兵模式
- 面試題
- Spring Boot整合Lettuce+Redisson實現布隆過濾器
- 集群
- Redis網絡IO模型
- 第十章 設計模式
- 設計模式-七大原則
- 設計模式-單例模式
- 設計模式-備忘錄模式
- 設計模式-原型模式
- 設計模式-責任鏈模式
- 設計模式-過濾模式
- 設計模式-觀察者模式
- 設計模式-工廠方法模式
- 設計模式-抽象工廠模式
- 設計模式-代理模式
- 第十一章 后端開發常用工具、庫
- Docker
- Docker安裝Mysql
- 第十二章 中間件
- ZooKeeper