Java 中的 BufferedReader 介绍_动力节点Java学院整理

BufferedReader 介绍

BufferedReader 是缓冲字符输入流。它继承于Reader。

BufferedReader 的作用是为其他字符输入流添加一些缓冲功能。

BufferedReader 函数列表

BufferedReader(Reader in)
BufferedReader(Reader in, int size)
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) 

BufferedReader 源码分析(基于jdk1.7.40) 

package java.io;
 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 read(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 -;
   // 若要“忽略换行符”,则进行相应处理
   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;
  }
  // 对read()的封装,添加了“同步处理”和“阻塞式读取”等功能
  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;
   }
  }
 }

说明:

要想读懂BufferReader的源码,就要先理解它的思想。BufferReader的作用是为其它Reader提供缓冲功能。创建BufferReader时,我们会通过它的构造函数指定某个Reader为参数。BufferReader会将该Reader中的数据分批读取,每次读取一部分到缓冲中;操作完缓冲中的这部分数据之后,再从Reader中读取下一部分的数据。

为什么需要缓冲呢?原因很简单,效率问题!缓冲中的数据实际上是保存在内存中,而原始数据可能是保存在硬盘或NandFlash中;而我们知道,从内存中读取数据的速度比从硬盘读取数据的速度至少快10倍以上。

那干嘛不干脆一次性将全部数据都读取到缓冲中呢?第一,读取全部的数据所需要的时间可能会很长。第二,内存价格很贵,容量不想硬盘那么大。

下面,我就BufferReader中最重要的函数fill()进行说明。其它的函数很容易理解,我就不详细介绍了,大家可以参考源码中的注释进行理解。我们先看看fill()的源码:

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

根据fill()中的if...else...,我将fill()分为4种情况进行说明。

情况1:读取完缓冲区的数据,并且缓冲区没有被标记

执行流程如下,

(01) 其它函数调用 fill(),来更新缓冲区的数据

(02) fill() 执行代码 if (markedChar <= UNMARKED) { ... }

为了方便分析,我们将这种情况下fill()执行的操作等价于以下代码:

private void fill() throws IOException {
  int dst;
  if (markedChar <= UNMARKED) {
   /* No mark */
   dst = 0;
  }
  int n;
  do {
   n = in.read(cb, dst, cb.length - dst);
  } while (n == 0);
  if (n > 0) {
   nChars = dst + n;
   nextChar = dst;
  }
 }

说明:

这种情况发生的情况是 — — Reader中有很长的数据,我们每次从中读取一部分数据到缓冲中进行操作。每次当我们读取完缓冲中的数据之后,并且此时BufferedReader没有被标记;那么,就接着从Reader(BufferReader提供缓冲功能的Reader)中读取下一部分的数据到缓冲中。

其中,判断是否读完缓冲区中的数据,是通过“比较nextChar和nChars之间大小”来判断的。其中,nChars 是缓冲区中字符的总的个数,而 nextChar 是缓冲区中下一个要读取的字符的位置。

判断BufferedReader有没有被标记,是通过“markedChar”来判断的。

理解这个思想之后,我们再对这种情况下的fill()的代码进行分析,就特别容易理解了。

(01) if (markedChar <= UNMARKED) 它的作用是判断“BufferedReader是否被标记”。若被标记,则dst=0。

(02) in.read(cb, dst, cb.length - dst) 等价于 in.read(cb, 0, cb.length),意思是从Reader对象in中读取cb.length个数据,并存储到缓冲区cb中,而且从缓冲区cb的位置0开始存储。该函数返回值等于n,也就是n表示实际读取的字符个数。若n=0(即没有读取到数据),则继续读取,直到读到数据为止。

(03) nChars=dst+n 等价于 nChars=n;意味着,更新缓冲区数据cb之后,设置nChars(缓冲区的数据个数)为n。

(04) nextChar=dst 等价于 nextChar=0;意味着,更新缓冲区数据cb之后,设置nextChar(缓冲区中下一个会被读取的字符的索引值)为0。

情况2:读取完缓冲区的数据,缓冲区的标记位置>0,并且“当前标记的长度”超过“标记上限(readAheadLimit)”

执行流程如下,

(01) 其它函数调用 fill(),来更新缓冲区的数据

(02) fill() 执行代码 if (delta >= readAheadLimit) { ... }

为了方便分析,我们将这种情况下fill()执行的操作等价于以下代码:

private void fill() throws IOException {
  int dst;
  if (markedChar > UNMARKED) {
   int delta = nextChar - markedChar;
   if (delta >= readAheadLimit) {
    markedChar = INVALIDATED;
    readAheadLimit = 0;
    dst = 0;
   }
  }
  int n;
  do {
   n = in.read(cb, dst, cb.length - dst);
  } while (n == 0);
 if (n > 0) {
   nChars = dst + n;
   nextChar = dst;
  }
 }

说明:

这种情况发生的情况是 — — BufferedReader中有很长的数据,我们每次从中读取一部分数据到缓冲区中进行操作。当我们读取完缓冲区中的数据之后,并且此时,BufferedReader存在标记时,同时,“当前标记的长度”大于“标记上限”;那么,就发生情况2。此时,我们会丢弃“标记”并更新缓冲区。

(01) delta = nextChar - markedChar;其中,delta就是“当前标记的长度”,它是“下一个被读取字符的位置”减去“被标记的位置”的差值。

(02) if (delta >= readAheadLimit);其中,当delta >= readAheadLimit,就意味着,“当前标记的长度”>=“标记上限”。为什么要有标记上限,即readAheadLimit的值到底有何意义呢?

我们标记一个位置之后,更新缓冲区的时候,被标记的位置会被保存;当我们不停的更新缓冲区的时候,被标记的位置会被不停的放大。然后内存的容量是有效的,我们不可能不限制长度的存储标记。所以,需要readAheadLimit来限制标记长度!

(03) in.read(cb, dst, cb.length - dst) 等价于 in.read(cb, 0, cb.length),意思是从Reader对象in中读取cb.length个数据,并存储到缓冲区cb中,而且从缓冲区cb的位置0开始存储。该函数返回值等于n,也就是n表示实际读取的字符个数。若n=0(即没有读取到数据),则继续读取,直到读到数据为止。

(04) nChars=dst+n 等价于 nChars=n;意味着,更新缓冲区数据cb之后,设置nChars(缓冲区的数据个数)为n。

(05) nextChar=dst 等价于 nextChar=0;意味着,更新缓冲区数据cb之后,设置nextChar(缓冲区中下一个会被读取的字符的索引值)为0。

情况3:读取完缓冲区的数据,缓冲区的标记位置>0,“当前标记的长度”没超过“标记上限(readAheadLimit)”,并且“标记上限(readAheadLimit)”小于/等于“缓冲的长度”;
执行流程如下,

(01) 其它函数调用 fill(),来更新缓冲区的数据

(02) fill() 执行代码 if (readAheadLimit <= cb.length) { ... }

为了方便分析,我们将这种情况下fill()执行的操作等价于以下代码:

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

说明:

这种情况发生的情况是 — — BufferedReader中有很长的数据,我们每次从中读取一部分数据到缓冲区中进行操作。当我们读取完缓冲区中的数据之后,并且此时,BufferedReader存在标记时,同时,“当前标记的长度”小于“标记上限”,并且“标记上限”小于/等于“缓冲区长度”;那么,就发生情况3。此时,我们保留“被标记的位置”(即,保留被标记位置开始的数据),并更新缓冲区(将新增的数据,追加到保留的数据之后)。

情况4:读取完缓冲区的数据,缓冲区的标记位置>0,“当前标记的长度”没超过“标记上限(readAheadLimit)”,并且“标记上限(readAheadLimit)”大于“缓冲的长度”;

执行流程如下,

(01) 其它函数调用 fill(),来更新缓冲区的数据

(02) fill() 执行代码 else { char ncb[] = new char[readAheadLimit]; ... }

为了方便分析,我们将这种情况下fill()执行的操作等价于以下代码:

private void fill() throws IOException {
  int dst;
  if (markedChar > UNMARKED) {
   int delta = nextChar - markedChar;
   if ((delta < readAheadLimit) && (readAheadLimit > cb.length) ) {
    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 == );
  if (n > ) {
   nChars = dst + n;
   nextChar = dst;
  }
 }

 说明:

这种情况发生的情况是 — — BufferedReader中有很长的数据,我们每次从中读取一部分数据到缓冲区中进行操作。当我们读取完缓冲区中的数据之后,并且此时,BufferedReader存在标记时,同时,“当前标记的长度”小于“标记上限”,并且“标记上限”大于“缓冲区长度”;那么,就发生情况4。此时,我们要先更新缓冲区的大小,然后再保留“被标记的位置”(即,保留被标记位置开始的数据),并更新缓冲区数据(将新增的数据,追加到保留的数据之后)。

示例代码

关于BufferedReader中API的详细用法,参考示例代码(BufferedReaderTest.java):

 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.InputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.FileNotFoundException;
 import java.lang.SecurityException;
 /**
 * BufferedReader 测试程序
 *
 *
 */
 public class BufferedReaderTest {
  private static final int LEN = 5;
  public static void main(String[] args) {
   testBufferedReader() ;
  }
  /**
  * BufferedReader的API测试函数
  */
  private static void testBufferedReader() {
   // 创建BufferedReader字符流,内容是ArrayLetters数组
   try {
    File file = new File("bufferedreader.txt");
    BufferedReader in =
     new BufferedReader(
      new FileReader(file));
    // 从字符流中读取5个字符。“abcde”
   for (int i=0; i<LEN; i++) {
     // 若能继续读取下一个字符,则读取下一个字符
     if (in.ready()) {
      // 读取“字符流的下一个字符”
      int tmp = in.read();
      System.out.printf("%d : %c\n", i, tmp);
     }
    }
    // 若“该字符流”不支持标记功能,则直接退出
    if (!in.markSupported()) {
     System.out.println("make not supported!");
     return ;
    }
    // 标记“当前索引位置”,即标记第6个位置的元素--“f”
   // 1024对应marklimit
    in.mark(1024);
   // 跳过22个字符。
    in.skip(22);
    // 读取5个字符
    char[] buf = new char[LEN];
   in.read(buf, 0, LEN);
    System.out.printf("buf=%s\n", String.valueOf(buf));
    // 读取该行剩余的数据
    System.out.printf("readLine=%s\n", in.readLine());
    // 重置“输入流的索引”为mark()所标记的位置,即重置到“f”处。
    in.reset();
   // 从“重置后的字符流”中读取5个字符到buf中。即读取“fghij”
    in.read(buf, , LEN);
    System.out.printf("buf=%s\n", String.valueOf(buf));
    in.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (SecurityException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  }
 }

程序中读取的bufferedreader.txt的内容如下:

abcdefghijklmnopqrstuvwxyz
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ

运行结果:

0 : a
1 : b
2 : c
3 : d
4 : e
buf=01234
readLine=56789
buf=fghij

以上所述是小编给大家介绍的Java 中的 BufferedReader 介绍_动力节点Java学院整理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Java BufferedWriter BufferedReader 源码分析

    一:BufferedWriter 1.类功能简介: BufferedWriter.缓存字符输出流.他的功能是为传入的底层字符输出流提供缓存功能.同样当使用底层字符输出流向目的地中写入字符或者字符数组时.每写入一次就要打开一次到目的地的连接.这样频繁的访问不断效率底下.也有可能会对存储介质造成一定的破坏.比如当我们向磁盘中不断的写入字节时.夸张一点.将一个非常大单位是G的字节数据写入到磁盘的指定文件中的.没写入一个字节就要打开一次到这个磁盘的通道.这个结果无疑是恐怖的.而当我们使用Buffered

  • Java中BufferedReader与BufferedWriter类的使用示例

    BufferedReader BufferedReader 是缓冲字符输入流.它继承于Reader. BufferedReader 的作用是为其他字符输入流添加一些缓冲功能. 创建BufferReader时,我们会通过它的构造函数指定某个Reader为参数.BufferReader会将该Reader中的数据分批读取,每次读取一部分到缓冲中:操作完缓冲中的这部分数据之后,再从Reader中读取下一部分的数据. 为什么需要缓冲呢?原因很简单,效率问题!缓冲中的数据实际上是保存在内存中,而原始数据可能

  • Java输入流Scanner/BufferedReader使用方法示例

    1.使用Scanner 使用时需要引入包import java.util.Scanner;首先定义Scanner对象 Scanner sc = new Scanner(System.in);如果要输入整数,则 int n = sc.nextInt();String类型的,则String temp = sc.next(); 比如: 复制代码 代码如下: import java.util.Scanner; public class Test {    @SuppressWarnings("resou

  • Java 中的 BufferedReader 介绍_动力节点Java学院整理

    BufferedReader 介绍 BufferedReader 是缓冲字符输入流.它继承于Reader. BufferedReader 的作用是为其他字符输入流添加一些缓冲功能. BufferedReader 函数列表 BufferedReader(Reader in) BufferedReader(Reader in, int size) void close() void mark(int markLimit) boolean markSupported() int read() int

  • Java 中的Printstream介绍_动力节点Java学院整理

    PrintStream 介绍 PrintStream 是打印输出流,它继承于FilterOutputStream. PrintStream 是用来装饰其它输出流.它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式. 与其他输出流不同,PrintStream 永远不会抛出 IOException:它产生的IOException会被自身的函数所捕获并设置错误标记, 用户可以通过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException

  • Java 中的 DataInputStream 介绍_动力节点Java学院整理

    DataInputStream 介绍 DataInputStream 是数据输入流.它继承于FilterInputStream. DataInputStream 是用来装饰其它输入流,它"允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型".应用程序可以使用DataOutputStream(数据输出流)写入由DataInputStream(数据输入流)读取的数据. DataInputStream 函数列表 DataInputStream(InputStream in

  • Java中的PrintWriter 介绍_动力节点Java学院整理

    PrintWriter 介绍 PrintWriter 是字符类型的打印输出流,它继承于Writer. PrintStream 用于向文本输出流打印对象的格式化表示形式.它实现在 PrintStream 中的所有 print 方法.它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入. PrintWriter 函数列表 PrintWriter(OutputStream out) PrintWriter(OutputStream out, boolean autoFlus

  • Java 中的CharArrayReader 介绍_动力节点Java学院整理

    CharArrayReader 介绍 CharArrayReader 是字符数组输入流.它和ByteArrayInputStream类似,只不过ByteArrayInputStream是字节数组输入流,而CharArray是字符数组输入流.CharArrayReader 是用于读取字符数组,它继承于Reader.操作的数据是以字符为单位! CharArrayReader 函数列表  CharArrayReader(char[] buf) CharArrayReader(char[] buf, i

  • Java 中的 BufferedWriter 介绍_动力节点Java学院整理

    BufferedWriter 介绍 BufferedWriter 是缓冲字符输出流.它继承于Writer. BufferedWriter 的作用是为其他字符输出流添加一些缓冲功能. BufferedWriter 函数列表  // 构造函数 BufferedWriter(Writer out) BufferedWriter(Writer out, int sz) void close() // 关闭此流,但要先刷新它. void flush() // 刷新该流的缓冲. void newLine()

  • 深入理解Java中的final关键字_动力节点Java学院整理

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使用final关键字的实例.final经常和static一起使用来声明常量,你也会看到final是如何改善应用性能的. final关键字的含义? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如

  • Java中的super关键字_动力节点Java学院整理

    一.super关键字 在JAVA类中使用super来引用父类的成分,用this来引用当前对象,如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象.怎么去引用里面的父类对象呢?使用super来引用,this指的是当前对象的引用,super是当前对象里面的父对象的引用. super关键字测试 package com.bjpowernode.test; /** * 父类 * * */ class FatherClass { public int value

  • Java中IO流简介_动力节点Java学院整理

    Java io简介 Java io系统的设计初衷,就是为了实现"文件.控制台.网络设备"这些io设置的通信.例如,对于一个文件,我们可以打开文件,然后进行读取和写入.在java 1.0中,java提供的类都是以字节(byte)为单位,例如,FileInputStream和FileOutputStream.而到了java 1.1,为了与国际化进行接轨,在java io中添加了许多以字符(Unicode)为单位进行操作的类. 在java io的称呼中,我们经常会提到"输入流&qu

  • Java中的 FilterInputStream简介_动力节点Java学院整理

    FilterInputStream 介绍 FilterInputStream 的作用是用来"封装其它的输入流,并为它们提供额外的功能".它的常用的子类有BufferedInputStream和DataInputStream. BufferedInputStream的作用就是为"输入流提供缓冲功能,以及mark()和reset()功能". DataInputStream 是用来装饰其它输入流,它"允许应用程序以与机器无关方式从底层输入流中读取基本 Java

随机推荐