調整 JavaTM I/O 性能
Glen McCluskey
翻譯
這篇文章討論和闡明了提供 JavaTM I/O 性能的多種技術
當我們討論Java I/O時
低級 I/O 問題
加速I/O的基本規則
緩沖
讀寫文本文件
格式化的代價
隨機訪問
高級I/O問題
壓縮
高速緩沖
分解
串行化
獲取文件信息
更多信息
加速I/O的基本規則
作為這個討論的開始
避免訪問磁盤
避免訪問底層的操作系統
避免方法調用
避免個別的處理字節和字符
很明顯這些規則不能在所有的問題上避免
方法
第一個方法簡單的使用FileInputStream的read方法:
import java
public class intro
public static void main(String args[]) {
if (args
System
System
}
try {
FileInputStream fis =
new FileInputStream(args[
int cnt =
int b;
while ((b = fis
if (b ==
cnt++;
}
fis
System
}
catch (IOException e) {
System
}
}
}
然而這個方法觸發了大量的底層運行時系統調用--FileInputStream
方法
第二種方法使用大緩沖區避免了上面的問題:
import java
public class intro
public static void main(String args[]) {
if (args
System
System
}
try {
FileInputStream fis =
new FileInputStream(args[
BufferedInputStream bis =
new BufferedInputStream(fis);
int cnt =
int b;
while ((b = bis
if (b ==
cnt++;
}
bis
System
}
catch (IOException e) {
System
}
}
}
BufferedInputStream
方法
第三種方法避免使用 BufferedInputStream 而直接緩沖
import java
public class intro
public static void main(String args[]) {
if (args
System
System
}
try {
FileInputStream fis =
new FileInputStream(args[
byte buf[] = new byte[
int cnt =
int n;
while ((n = fis
for (int i =
if (buf[i] == '\n')
cnt++;
}
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
對於一個1 MB 的輸入文件,以秒為單位的執行時間是:
intro1 6.9
intro2 0.9
intro3 0.4
或者說在最慢的方法和最快的方法間是17比1的不同。tw.wINgwIT.cOm
這個巨大的加速並不能證明你應該總是使用第三種方法,即自己做緩沖。這可能是一個錯誤的傾向特別是在處理文件結束事件時沒有仔細的實現。在可讀性上它也沒有其它方法好。但是記住時間花費在哪兒了以及在必要的時候如何矯正是很有用。
方法2 或許是對於大多應用的 "正確" 方法.
緩沖
方法 2 和 3 使用了緩沖技術, 大塊文件被從磁盤讀取,然後每次訪問一個字節或字符。緩沖是一個基本而重要的加速I/O 的技術,而且有幾個類支持緩沖(BufferedInputStream 用於字節, BufferedReader 用於字符)。
一個明顯得問題是: 緩沖區越大I/O越快嗎?典型的Java緩沖區長1024 或者 2048 字節,一個更大的緩沖區有可能加速 I/O但是只能占很小的比重,大約5 到10%。
方法4: 整個文件
緩沖的極端情況是事先決定整個文件的長度,然後讀取整個文件:
import java.io.*;
public class readfile {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
int len = (int)(new File(args[0]).length());
FileInputStream fis =
new FileInputStream(args[0]);
byte buf[] = new byte[len];
fis.read(buf);
fis.close();
int cnt = 0;
for (int i = 0; i < len; i++) {
if (buf[i] == '\n')
cnt++;
}
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
這個方法很方便,在這裡文件被當作一個字節數組。但是有一個明顯得問題是有可能沒有讀取一個巨大的文件的足夠的內存。
緩沖的另一個方面是向窗口終端的文本輸出。缺省情況下, System.out ( 一個PrintStream) 是行緩沖的,這意味著在遇到一個新行符後輸出緩沖區被提交。對於交互來說這是很重要的,在那種情況下你可能喜歡在實際的輸出前顯示一個輸入提示。
方法 5: 關閉行緩沖
行緩沖可以被禁止,像下面的例子那樣:
import java.io.*;
public class bufout {
public static void main(String args[]) {
FileOutputStream fdout =
new FileOutputStream(FileDescriptor.out);
BufferedOutputStream bos =
new BufferedOutputStream(fdout, 1024);
PrintStream ps =
new PrintStream(bos, false);
System.setOut(ps);
final int N = 100000;
for (int i = 1; i <= N; i++)
System.out.println(i);
ps.close();
}
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19573.html