国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java BufferedWriter BufferedReader 源碼分析

2019-11-26 14:06:04
字體:
來源:轉載
供稿:網友

一:BufferedWriter

 1、類功能簡介:

        BufferedWriter、緩存字符輸出流、他的功能是為傳入的底層字符輸出流提供緩存功能、同樣當使用底層字符輸出流向目的地中寫入字符或者字符數組時、每寫入一次就要打開一次到目的地的連接、這樣頻繁的訪問不斷效率底下、也有可能會對存儲介質造成一定的破壞、比如當我們向磁盤中不斷的寫入字節時、夸張一點、將一個非常大單位是G的字節數據寫入到磁盤的指定文件中的、沒寫入一個字節就要打開一次到這個磁盤的通道、這個結果無疑是恐怖的、而當我們使用BufferedWriter將底層字符輸出流、比如FileReader包裝一下之后、我們可以在程序中先將要寫入到文件中的字符寫入到BufferedWriter的內置緩存空間中、然后當達到一定數量時、一次性寫入FileReader流中、此時、FileReader就可以打開一次通道、將這個數據塊寫入到文件中、這樣做雖然不可能達到一次訪問就將所有數據寫入磁盤中的效果、但也大大提高了效率和減少了磁盤的訪問量!這就是其意義所在、 他的具體工作原理在這里簡單提一下:這里可能說的比較亂、具體可以看源碼、不懂再回頭看看這里、當程序中每次將字符或者字符數組寫入到BufferedWriter中時、都會檢查BufferedWriter中的緩存字符數組buf(buf的大小是默認的或者在創建bw時指定的、一般使用默認的就好)是否存滿、如果沒有存滿則將字符寫入到buf中、如果存滿、則調用底層的writer(char[] b, int off, int len)將buf中的所有字符一次性寫入到底層out中、如果寫入的是字符數組、如果buf中已滿則同上面滿的時候的處理、如果能夠存下寫入的字符數組、則存入buf中、如果存不下、并且要寫入buf的字符個數小于buf的長度、則將buf中所有字符寫入到out中、然后將要寫入的字符存放到buf中(從下標0開始存放)、如果要寫入out中的字符超過buf的長度、則直接寫入out中、

2、BufferedWriter  API簡介:

    A:關鍵字  private Writer out;		 底層字符輸出流    private char cb[];		 緩沖數組    private int nChars, nextChar;		 nChars--cb的size,nextChar--cb中下一個字符的下標  private static int defaultCharBufferSize = 8192;		 默認cb大小  private String lineSeparator;		換行符、用于newLine方法。不同平臺具有不同的值。    B:構造方法  BufferedWriter(Writer out)		使用默認cb大小創建BufferedWriter bw。    BufferedWriter(Writer out, int sz)		使用默認cb大小創建BufferedWriter bw。    C:一般方法  void close()		關閉此流、釋放與此流有關的資源。    void flushBuffer()		將cb中緩存的字符flush到底層out中、    void flush()	刷新此流、同時刷新底層out流    void newLine()		寫入一個換行符。    void write(int c)		將一個單個字符寫入到cb中。    void write(char cbuf[], int off, int len)	將一個從下標off開始長度為len個字符寫入cb中    void write(String s, int off, int len)		將一個字符串的一部分寫入cb中

3、源碼分析

package com.chy.io.original.code;import java.io.IOException;import java.io.PrintWriter;/** * 為字符輸出流提供緩沖功能、提高效率。可以使用指定字符緩沖數組大小也可以使用默認字符緩沖數組大小。 */public class BufferedWriter extends Writer {	//底層字符輸出流  private Writer out;  //緩沖數組  private char cb[];  //nChars--cb中總的字符數,nextChar--cb中下一個字符的下標  private int nChars, nextChar;  //默認cb大小  private static int defaultCharBufferSize = 8192;  /**   * Line separator string. This is the value of the line.separator   * property at the moment that the stream was created.   * 換行符、用于newLine方法。不同平臺具有不同的值。   */  private String lineSeparator;  /**   * 使用默認cb大小創建BufferedWriter bw。   */  public BufferedWriter(Writer out) {  	this(out, defaultCharBufferSize);  }  /**   * 使用指定cb大小創建br、初始化相關字段   */  public BufferedWriter(Writer out, int sz) {		super(out);			if (sz <= 0)			  throw new IllegalArgumentException("Buffer size <= 0");			this.out = out;			cb = new char[sz];			nChars = sz;			nextChar = 0;			//獲取不同平臺下的換行符表示方式。			lineSeparator =	(String) java.security.AccessController.doPrivileged(		        new sun.security.action.GetPropertyAction("line.separator"));  }  /** 檢測底層字符輸出流是否關閉*/  private void ensureOpen() throws IOException {		if (out == null)		  throw new IOException("Stream closed");  }  /**   * 將cb中緩存的字符flush到底層out中、但是不flush底層out中的字符。   * 并且將cb清空。   */  void flushBuffer() throws IOException {		synchronized (lock) {		  ensureOpen();		  if (nextChar == 0)		  	return;		  out.write(cb, 0, nextChar);		  nextChar = 0;		}  }  /**   * 將一個單個字符寫入到cb中。   */  public void write(int c) throws IOException {		synchronized (lock) {		  ensureOpen();		  if (nextChar >= nChars)			flushBuffer();		  cb[nextChar++] = (char) c;		}  }  /**   * Our own little min method, to avoid loading java.lang.Math if we've run   * out of file descriptors and we're trying to print a stack trace.   */  private int min(int a, int b) {	if (a < b) return a;	return b;  }  /**   * 將一個從下標off開始長度為len個字符寫入cb中   */  public void write(char cbuf[], int off, int len) throws IOException {		synchronized (lock) {		  ensureOpen();	      if ((off < 0) || (off > cbuf.length) || (len < 0) ||	        ((off + len) > cbuf.length) || ((off + len) < 0)) {	        throw new IndexOutOfBoundsException();	      } else if (len == 0) {	        return;	      } 			  if (len >= nChars) {				/* 如果len大于cb的長度、那么就直接將cb中現有的字符和cbuf中的字符寫入out中、				 * 而不是寫入cb、再寫入out中 。				 */				flushBuffer();				out.write(cbuf, off, len);				return;		  }			  int b = off, t = off + len;		  while (b < t) {				int d = min(nChars - nextChar, t - b);				System.arraycopy(cbuf, b, cb, nextChar, d);				b += d;				nextChar += d;				if (nextChar >= nChars)				  flushBuffer();		  }		}  }  /**   * 將一個字符串的一部分寫入cb中   */  public void write(String s, int off, int len) throws IOException {	synchronized (lock) {	  ensureOpen();	  int b = off, t = off + len;	  while (b < t) {		int d = min(nChars - nextChar, t - b);		s.getChars(b, b + d, cb, nextChar);		b += d;		nextChar += d;		if (nextChar >= nChars)		  flushBuffer();	  }	}  }  /**   * 寫入一個換行符。   */  public void newLine() throws IOException {  	write(lineSeparator);  }  /**   * 刷新此流、同時刷新底層out流   */  public void flush() throws IOException {		synchronized (lock) {		  flushBuffer();		  out.flush();		}  }  /**   * 關閉此流、釋放與此流有關的資源。   */  public void close() throws IOException {		synchronized (lock) {		  if (out == null) {			return;		  }		  try {		    flushBuffer();		  } finally {		    out.close();		    out = null;		    cb = null;		  }		}  }}

 4、實例演示:與下面的BufferedReader結合使用實現字符類型的文件的拷貝。

二:BufferedReader

 1、類功能簡介:

        緩沖字符輸入流、他的功能是為傳入的底層字符輸入流提供緩沖功能、他會通過底層字符輸入流(in)中的字符讀取到自己的buffer中(內置緩存字符數組)、然后程序調用BufferedReader的read方法將buffer中的字符讀取到程序中、當buffer中的字符被讀取完之后、BufferedReader會從in中讀取下一個數據塊到buffer中供程序讀取、直到in中數據被讀取完畢、這樣做的好處一是提高了讀取的效率、二是減少了打開存儲介質的連接次數、詳細的原因下面BufferedWriter有說到。其有個關鍵的方法fill()就是每當buffer中數據被讀取完之后從in中將數據填充到buffer中、程序從內存中讀取數據的速度是從磁盤中讀取的十倍!這是一個很恐怖的效率的提升、同時我們也不能無禁止的指定BufferedReader的buffer大小、畢竟、一次性讀取in中耗時較長、二是內存價格相對昂貴、我們能做的就是盡量在其中找到合理點。一般也不用我們費這個心、創建BufferedReader時使用buffer的默認大小就好。

2、BufferedReader  API簡介:

 A:構造方法  BufferedReader(Reader in, int sz)		根據指定大小和底層字符輸入流創建BufferedReader。br    BufferedReader(Reader in)		使用默認大小創建底層輸出流的緩沖流     B:一般方法  void close()	關閉此流、釋放與此流有關的所有資源    void mark(int readAheadLimit)	標記此流此時的位置    boolean markSupported()		判斷此流是否支持標記    void reset()	重置in被最后一次mark的位置    boolean ready()		判斷此流是否可以讀取字符    int read()		讀取單個字符、以整數形式返回。如果讀到in的結尾則返回-1。    int read(char[] cbuf, int off, int len)	將in中len個字符讀取到cbuf從下標off開始長度len中    String readLine()	讀取一行    long skip(long n)		丟棄in中n個字符

 3、源碼分析

package com.chy.io.original.code;import java.io.IOException;/** * 為底層字符輸入流添加字符緩沖cb數組。提高效率 * @version 	1.1, 13/11/17 * @author		andyChen */public class BufferedReader extends Reader {  private Reader in;   private char cb[];  private int nChars, nextChar;  private static final int INVALIDATED = -2;  private static final int UNMARKED = -1;  private int markedChar = UNMARKED;  private int readAheadLimit = 0; /* Valid only when markedChar > 0 */  /** If the next character is a line feed, skip it */  private boolean skipLF = false;  /** The skipLF flag when the mark was set */  private boolean markedSkipLF = false;  private static int defaultCharBufferSize = 8192;  private static int defaultExpectedLineLength = 80;  /**   * 根據指定大小和底層字符輸入流創建BufferedReader。br   */  public BufferedReader(Reader in, int sz) {		super(in);		if (sz <= 0)		  throw new IllegalArgumentException("Buffer size <= 0");		this.in = in;		cb = new char[sz];		nextChar = nChars = 0;  }  /**   * 使用默認大小創建底層輸出流的緩沖流   */  public BufferedReader(Reader in) {  	this(in, defaultCharBufferSize);  }  /** 檢測底層字符輸入流in是否關閉 */  private void ensureOpen() throws IOException {		if (in == null)		  throw new IOException("Stream closed");  }  /**   * 填充cb。   */  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 {		  n = in.read(cb, dst, cb.length - dst);		} while (n == 0);		if (n > 0) {		  nChars = dst + n;		  nextChar = dst;		}  }  /**   * 讀取單個字符、以整數形式返回。如果讀到in的結尾則返回-1。   */  public int read() throws IOException {		synchronized (lock) {		  ensureOpen();		  for (;;) {			if (nextChar >= nChars) {			  fill();			  if (nextChar >= nChars)				return -1;			}			if (skipLF) {			  skipLF = false;			  if (cb[nextChar] == '/n') {				nextChar++;				continue;			  }			}			return cb[nextChar++];		  }		}  }  /**   * 將in中len個字符讀取到cbuf從下標off開始長度len中   */  private int read1(char[] cbuf, int off, int len) throws IOException {		if (nextChar >= nChars) {		  /* If the requested length is at least as large as the buffer, and		    if there is no mark/reset activity, and if line feeds are not		    being skipped, do not bother to copy the characters into the		    local buffer. In this way buffered streams will cascade		    harmlessly. */		  if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {			return in.read(cbuf, off, len);		  }		  fill();		}		if (nextChar >= nChars) return -1;		if (skipLF) {		  skipLF = false;		  if (cb[nextChar] == '/n') {			nextChar++;			if (nextChar >= nChars)			  fill();			if (nextChar >= nChars)			  return -1;		  }		}		int n = Math.min(len, nChars - nextChar);		System.arraycopy(cb, nextChar, cbuf, off, n);		nextChar += n;		return n;  }  /**   * 將in中len個字符讀取到cbuf從下標off開始長度len中   */  public int read(char cbuf[], int off, int len) throws IOException {    synchronized (lock) {	  ensureOpen();      if ((off < 0) || (off > cbuf.length) || (len < 0) ||        ((off + len) > cbuf.length) || ((off + len) < 0)) {        throw new IndexOutOfBoundsException();      } else if (len == 0) {        return 0;      }	  int n = read1(cbuf, off, len);	  if (n <= 0) return n;	  while ((n < len) && in.ready()) {		int n1 = read1(cbuf, off + n, len - n);		if (n1 <= 0) break;		n += n1;	  }	  return n;	}  }  /**   * 從in中讀取一行、是否忽略換行符   */  String readLine(boolean ignoreLF) throws IOException {		StringBuffer s = null;		int startChar;	    synchronized (lock) {      ensureOpen();	  boolean omitLF = ignoreLF || skipLF;		bufferLoop:		for (;;) {				if (nextChar >= nChars)			  fill();			if (nextChar >= nChars) { /* EOF */			  if (s != null && s.length() > 0)				return s.toString();			  else				return null;			}			boolean eol = false;			char c = 0;			int i;		        /* Skip a leftover '/n', if necessary */			if (omitLF && (cb[nextChar] == '/n')) 	          nextChar++;			skipLF = false;			omitLF = false;			  charLoop:			for (i = nextChar; i < nChars; i++) {			  c = cb[i];			  if ((c == '/n') || (c == '/r')) {				eol = true;				break charLoop;			  }			}				startChar = nextChar;			nextChar = i;				if (eol) {			  String str;			  if (s == null) {				str = new String(cb, startChar, i - startChar);			  } else {				s.append(cb, startChar, i - startChar);				str = s.toString();			  }			  nextChar++;			  if (c == '/r') {				skipLF = true;			  }			  return str;			}						if (s == null) 			  s = new StringBuffer(defaultExpectedLineLength);			s.append(cb, startChar, i - startChar);		  }    }  }  /**   * 從in中讀取一行、   */  public String readLine() throws IOException {    return readLine(false);  }  /**   * 丟棄in中n個字符   */  public long skip(long n) throws IOException {		if (n < 0L) {		  throw new IllegalArgumentException("skip value is negative");		}		synchronized (lock) {		  ensureOpen();		  long r = n;		  while (r > 0) {			if (nextChar >= nChars)			  fill();			if (nextChar >= nChars)	/* EOF */			  break;			if (skipLF) {			  skipLF = false;			  if (cb[nextChar] == '/n') {				nextChar++;			  }			}			long d = nChars - nextChar;			if (r <= d) {			  nextChar += r;			  r = 0;			  break;			}			else {			  r -= d;			  nextChar = nChars;			}		  }		  return n - r;		}  }  /**   * 判斷cb中是否為空、或者底層in中是否有可讀字符。   */  public boolean ready() throws IOException {		synchronized (lock) {		  ensureOpen();			  /* 		   * If newline needs to be skipped and the next char to be read		   * is a newline character, then just skip it right away.		   */		  if (skipLF) {			/* Note that in.ready() will return true if and only if the next 			 * read on the stream will not block.			 */			if (nextChar >= nChars && in.ready()) {			  fill();			}			if (nextChar < nChars) {			  if (cb[nextChar] == '/n') 				nextChar++;			  skipLF = false;			} 		  }		  return (nextChar < nChars) || in.ready();		}  }  /**   * 判斷此流是否支持標記   */  public boolean markSupported() {  	return true;  }  /**   * 標記此流此時的位置、當調用reset方法失效前最多允許讀取readAheadLimit個字符。   */  public void mark(int readAheadLimit) throws IOException {		if (readAheadLimit < 0) {		  throw new IllegalArgumentException("Read-ahead limit < 0");		}		synchronized (lock) {		  ensureOpen();		  this.readAheadLimit = readAheadLimit;		  markedChar = nextChar;		  markedSkipLF = skipLF;		}  }  /**   * 重置in被最后一次mark的位置。即下一個字符從被最后一次mark的位置開始讀取。   */  public void reset() throws IOException {		synchronized (lock) {		  ensureOpen();		  if (markedChar < 0)			throw new IOException((markedChar == INVALIDATED)					   ? "Mark invalid"					   : "Stream not marked");		  nextChar = markedChar;		  skipLF = markedSkipLF;		}  }  //關閉此流、釋放與此流有關的所有資源  public void close() throws IOException {		synchronized (lock) {		  if (in == null)			return;		  in.close();		  in = null;		  cb = null;		}  }}

4、實例演示:

package com.chy.io.original.test;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class BufferedWriterAndBufferedReaderTest {	/**	 * 這里對這兩個類的測試比較簡單、就是對文件字符流進行包裝、實現文件拷貝	 * 有興趣的可以測試一下效率、、偷個懶、、可無視	 */	public static void main(String[] args) throws IOException{		File resouceFile = new File("D://test.txt");		File targetFile = new File("E://copyOftest.txt");				BufferedReader br = new BufferedReader(new FileReader(resouceFile));		BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile));				char[] cbuf = new char[1024];		int n = 0;		while((n = br.read(cbuf)) != -1){			bw.write(cbuf, 0, n);		}		//不要忘記刷新和關閉流、否則一方面資源沒有及時釋放、另一方面有可能照成數據丟失		br.close();		bw.flush();		bw.close();	}}

總結:

        對于BufferedReader、BufferedWriter、本質就是為底層字符輸入輸出流添加緩沖功能、先將底層流中的要讀取或者要寫入的數據先以一次讀取一組的形式來講數據讀取或者寫入到buffer中、再對buffer進行操作、這樣不但效率、還能節省資源。最后、在程序中、出于效率的考慮、也應為低級流使用這兩個類進行裝飾一下、而不是直接拿著流直接上、覺得能實現就行。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 沁水县| 乌鲁木齐县| 江源县| 屏山县| 岗巴县| 偃师市| 通辽市| 乌审旗| 通道| 大名县| 农安县| 无锡市| 明光市| 闽清县| 红桥区| 纳雍县| 霞浦县| 灵石县| 新田县| 丹凤县| 辛集市| 桓台县| 泾阳县| 建昌县| 靖宇县| 界首市| 固阳县| 长丰县| 黎川县| 武汉市| 龙陵县| 铜梁县| 铜陵市| 日土县| 宁安市| 台北市| 内丘县| 德化县| 牡丹江市| 宝兴县| 长沙县|