Java BufferedReader类
BufferedReader 是缓冲字符输入流,它继承于Reader,它的作用是为其他字符输入流添加一些缓冲功能。
构造函数
BufferedReader(Reader in) :创建一个使用默认大小输入缓冲区的缓冲字符输入流。 BufferedReader(Reader in, int sz) :创建一个使用指定大小输入缓冲区的缓冲字符输入流,大多数情况下,默认值就足够大了。
方法
void close() void mark(int markLimit) boolean markSupported() int read() int read(char[] buffer, int offset, int length) String readLine() boolean ready() void reset() long skip(long charCount)
读取数据方法
1. 从标准输入上建立输入流
BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
System.in 表示标准输入,一般指键盘。
建立输入流,从标准输入读取数据到缓冲区中。当在标准输入中输入一行字符串时,按回车之后,这行数据就会被读取到缓冲区中。
2. 从Java的 InputStream中建立输入流
BufferedReader localReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
从InputStream中输入与从键盘输入是有区别的,InputStream流可以关闭(异常关闭或正常关闭),而对于键盘而言,没有关闭的概念,只要你从键盘敲入字符并按回车就会输入一行字符。
例子
String msg = null; while ((msg = localReader.readLine()) != null) { System.out.println(msg);//打印从标准输入读取到的数据 process(msg); if (msg.equals("bye"))//当输入 bye 时 结束 break; }
BufferedReader 使用 readLine方法读取数据时,每次读取一行。以回车换行标记一行数据的结束。使用if语句来判断用户是否在标准输入中输入了bye。若输入了bye之后,就跳出while循环。若没有if语句,while循环就不会终止。
源码分析
public class BufferedReader extends Reader { private Reader in; // 字符缓冲区 private char cb[]; // nChars 是cb缓冲区中字符的总的个数 // nextChar 是下一个要读取的字符在cb缓冲区中的位置 private int nChars, nextChar; // 表示“标记无效”。它与UNMARKED的区别是: // (01) UNMARKED 是压根就没有设置过标记。 // (02) 而INVALIDATED是设置了标记,但是被标记位置太长,导致标记无效! 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 */ // skipLF(即skip Line Feed)是“是否忽略换行符”标记 private boolean skipLF = false; // 设置“标记”时,保存的skipLF的值 private boolean markedSkipLF = false; // 默认字符缓冲区大小 private static int defaultCharBufferSize = 8192; // 默认每一行的字符个数 private static int defaultExpectedLineLength = 80; // 创建“Reader”对应的BufferedReader对象,sz是BufferedReader的缓冲区大小 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; } // 创建“Reader”对应的BufferedReader对象,默认的BufferedReader缓冲区大小是8k public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } // 确保“BufferedReader”是打开状态 private void ensureOpen() throws IOException { if (in == null) throw new IOException("Stream closed"); } // 填充缓冲区函数。有以下两种情况被调用: // (01) 缓冲区没有数据时,通过fill()可以向缓冲区填充数据。 // (02) 缓冲区数据被读完,需更新时,通过fill()可以更新缓冲区的数据。 private void fill() throws IOException { // dst表示“cb中填充数据的起始位置”。 int dst; if (markedChar <= UNMARKED) { // 没有标记的情况,则设dst=0。 dst = 0; } else { // delta表示“当前标记的长度”,它等于“下一个被读取字符的位置”减去“标记的位置”的差值; int delta = nextChar - markedChar; if (delta >= readAheadLimit) { // 若“当前标记的长度”超过了“标记上限(readAheadLimit)”, // 则丢弃标记! markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else { if (readAheadLimit <= cb.length) { // 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”, // 并且“标记上限(readAheadLimit)”小于/等于“缓冲的长度”; // 则先将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。 System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else { // 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”, // 并且“标记上限(readAheadLimit)”大于“缓冲的长度”; // 则重新设置缓冲区大小,并将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。 char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } // 更新nextChar和nChars nextChar = nChars = delta; } } int n; do { // 从“in”中读取数据,并存储到字符数组cb中; // 从cb的dst位置开始存储,读取的字符个数是cb.length - dst // n是实际读取的字符个数;若n==0(即一个也没读到),则继续读取! n = in.read(cb, dst, cb.length - dst); } while (n == 0); // 如果从“in”中读到了数据,则设置nChars(cb中字符的数目)=dst+n, // 并且nextChar(下一个被读取的字符的位置)=dst。 if (n > 0) { nChars = dst + n; nextChar = dst; } } // 从BufferedReader中读取一个字符,该字符以int的方式返回 public int read() throws IOException { synchronized (lock) { ensureOpen(); for (;;) { // 若“缓冲区的数据已经被读完”, // 则先通过fill()更新缓冲区数据 if (nextChar >= nChars) { fill(); if (nextChar >= nChars) return -1; } // 若要“忽略换行符”, // 则对下一个字符是否是换行符进行处理。 if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; continue; } } // 返回下一个字符 return cb[nextChar++]; } } } // 将缓冲区中的数据写入到数组cbuf中。off是数组cbuf中的写入起始位置,len是写入长度 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; } // 对read1()的封装,添加了“同步处理”和“阻塞式读取”等功能 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; } } // 读取一行数据。ignoreLF是“是否忽略换行符” 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); } } } // 读取一行数据。不忽略换行符 public String readLine() throws IOException { return readLine(false); } // 跳过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; } } // “下一个字符”是否可读 public boolean ready() throws IOException { synchronized (lock) { ensureOpen(); // 若忽略换行符为true; // 则判断下一个符号是否是换行符,若是的话,则忽略 if (skipLF) { if (nextChar >= nChars && in.ready()) { fill(); } if (nextChar < nChars) { if (cb[nextChar] == '\n') nextChar++; skipLF = false; } } return (nextChar < nChars) || in.ready(); } } // 始终返回true。因为BufferedReader支持mark(), reset() public boolean markSupported() { return true; } // 标记当前BufferedReader的下一个要读取位置。关于readAheadLimit的作用,参考后面的说明。 public void mark(int readAheadLimit) throws IOException { if (readAheadLimit < 0) { throw new IllegalArgumentException("Read-ahead limit < 0"); } synchronized (lock) { ensureOpen(); // 设置readAheadLimit this.readAheadLimit = readAheadLimit; // 保存下一个要读取的位置 markedChar = nextChar; // 保存“是否忽略换行符”标记 markedSkipLF = skipLF; } } // 重置BufferedReader的下一个要读取位置, // 将其还原到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; } } }
例子
public class BufferedReaderDemo01{ public static void main(String args[]){ BufferedReader buf = null ; // 声明对象 buf = new BufferedReader(new InputStreamReader(System.in)) ; // 将字节流变为字符流 String str = null ; // 接收输入内容 System.out.print("请输入内容:") ; try{ str = buf.readLine() ; // 读取一行数据 }catch(IOException e){ e.printStackTrace() ; // 输出信息 } System.out.println("输入的内容为:" + str) ; } };
版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。