栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java BufferedWriter BufferedReader 源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java BufferedWriter BufferedReader 源码分析

一: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;

  
  private String lineSeparator;

  
  public BufferedWriter(Writer out) {
  	this(out, defaultCharBufferSize);
  }

  
  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");
  }

  
  void flushBuffer() throws IOException {
		synchronized (lock) {
		  ensureOpen();
		  if (nextChar == 0)
		  	return;
		  out.write(cb, 0, nextChar);
		  nextChar = 0;
		}
  }

  
  public void write(int c) throws IOException {
		synchronized (lock) {
		  ensureOpen();
		  if (nextChar >= nChars)
			flushBuffer();
		  cb[nextChar++] = (char) c;
		}
  }

  
  private int min(int a, int b) {
	if (a < b) return a;
	return b;
  }

  
  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) {
				
				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();
		  }
		}
  }

  
  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);
  }

  
  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;



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; 

  
  private boolean skipLF = false;

  
  private boolean markedSkipLF = false;

  private static int defaultCharBufferSize = 8192;
  private static int defaultExpectedLineLength = 80;

  
  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);
  }

  
  private void ensureOpen() throws IOException {
		if (in == null)
		  throw new IOException("Stream closed");
  }

  
  private void fill() throws IOException {
		int dst;
		if (markedChar <= UNMARKED) {
		  
		  dst = 0;
		} else {
		  
		  int delta = nextChar - markedChar;
		  if (delta >= readAheadLimit) {
			
			markedChar = INVALIDATED;
			readAheadLimit = 0;
			dst = 0;
		  } else {
			if (readAheadLimit <= cb.length) {
			  
			  System.arraycopy(cb, markedChar, cb, 0, delta);
			  markedChar = 0;
			  dst = delta;
			} else {
			  
			  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;
		}
  }

  
  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++];
		  }
		}
  }

  
  private int read1(char[] cbuf, int off, int len) throws IOException {
		if (nextChar >= nChars) {
		  
		  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;
  }

  
  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;
	}
  }

  
  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) { 
			  if (s != null && s.length() > 0)
				return s.toString();
			  else
				return null;
			}
			boolean eol = false;
			char c = 0;
			int i;
	
	 
			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);
		  }
    }
  }

  
  public String readLine() throws IOException {
    return readLine(false);
  }

  
  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)	
			  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;
		}
  }

  
  public boolean ready() throws IOException {
		synchronized (lock) {
		  ensureOpen();
	
		  
		  if (skipLF) {
			
			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;
  }

  
  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;
		}
  }

  
  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进行操作、这样不但效率、还能节省资源。最后、在程序中、出于效率的考虑、也应为低级流使用这两个类进行装饰一下、而不是直接拿着流直接上、觉得能实现就行。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/149642.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号