基本概念
Java有字節流和字符流兩種:
字節流:InputStream/OutputStream字符流:Reader/Writer
字符流處理的單元爲2個字節的Unicode字符,分別操作字符、字符數組或字符串,而字節流處理單元爲1個字節,操作字節和字節數組。所以字符流是由Java虛擬機將字節轉化爲2個字節的Unicode字符爲單位的字符而成的,所以它對多國語言支持性比較好!如果是音頻文件、圖片、歌曲,就用字節流好點,如果是關係到中文(文本)的,用字符流好點.
處理字節流
InputStream 是字節輸入流的所有類的超類,一般我們使用它的子類,如FileInputStream等.
OutputStream是字節輸出流的所有類的超類,一般我們使用它的子類,如FileOutputStream等.
處理字符流
Reader和Writer是所有字符流類的的抽象基類,用於簡化對字符串的輸入輸出編程,即用於讀寫文本數據
字節流和字符流的相互轉換
1.從字節流到字符流
InputStreamReader 是字節流通向字符流的橋樑,它將字節流轉換爲字符流.
OutputStreamWriter是字符流通向字節流的橋樑,它將字符流轉換爲字節流.
2.從字符流到字節流
可以從字符流中獲取char[]數組,轉換爲String,然後調用String的API函數getBytes() 獲取到byte[],然後就可以通過ByteArrayInputStream、ByteArrayOutputStream來實現到字節流的轉換。
BufferedReader BufferedWriter
BufferedReader 由Reader類擴展而來,提供通用的緩衝方式文本讀取,readLine讀取一個文本行,從字符輸入流中讀取文本,緩衝各個字符,從而提供字符、數組和行的高效讀取。
實際上,BufferedWriter是對OutputStreamWriter的封裝,BufferedReader是對InputStreamReader的封裝,封裝格式:
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader in= new BufferedReader(new InputStreamReader(System.in);
我們從BufferedReader源碼中可以看出:
public class BufferedReader extends Reader {
private Reader in;
private char cb[];
...
private static int defaultCharBufferSize = 8192;
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in; /* 對Reader進行封裝 */
cb = new char[sz];
nextChar = nChars = 0;
}
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
/**
* Fills the input buffer, taking the mark into account if it is valid.
*/
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
/* 從in中讀取字符到緩衝區cb中 */
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
/**
* Reads a single character.
*
* @return The character read, as an integer in the range
* 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
* end of the stream has been reached
* @exception IOException If an I/O error occurs
*/
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
if (nextChar >= nChars) {
fill(); /* 從字符流in中讀取字符填充cb緩衝區 */
if (nextChar >= nChars)
return -1;
}
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
return cb[nextChar++]; /* 從緩衝區中讀取字符 */
}
}
}
...
}
BufferedReader的最大特點就是緩衝區的設置。通常Reader 所作的每個讀取請求都會導致對底層字符或字節流進行相應的讀取請求,如果沒有緩衝,則每次調用 read() 或 readLine() 都會導致從文件中讀取字節,並將其轉換爲字符後返回,而這是極其低效的。 使用BufferedReader可以指定緩衝區的大小,或者可使用默認的大小。大多數情況下,默認值就足夠大了。
因此,建議用 BufferedReader 包裝所有其 read() 操作可能開銷很高的 Reader(如 FileReader 和InputStreamReader)。