溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

BufferedReader如何在Java項(xiàng)目中使用

發(fā)布時(shí)間:2020-11-19 16:20:52 來源:億速云 閱讀:124 作者:Leah 欄目:編程語(yǔ)言

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān) BufferedReader如何在Java項(xiàng)目中使用,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

BufferedReader 介紹

BufferedReader 是緩沖字符輸入流。它繼承于Reader。

BufferedReader 的作用是為其他字符輸入流添加一些緩沖功能。

BufferedReader 函數(shù)列表

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 源碼分析

package java.io;
 public class BufferedReader extends Reader {
  private Reader in;
  // 字符緩沖區(qū)
  private char cb[];
  // nChars 是cb緩沖區(qū)中字符的總的個(gè)數(shù)
  // nextChar 是下一個(gè)要讀取的字符在cb緩沖區(qū)中的位置
  private int nChars, nextChar;
  // 表示“標(biāo)記無效”。它與UNMARKED的區(qū)別是:
  // (01) UNMARKED 是壓根就沒有設(shè)置過標(biāo)記。
  // (02) 而INVALIDATED是設(shè)置了標(biāo)記,但是被標(biāo)記位置太長(zhǎng),導(dǎo)致標(biāo)記無效!
 private static final int INVALIDATED = -2;
  // 表示沒有設(shè)置“標(biāo)記”
 private static final int UNMARKED = -1;
  // “標(biāo)記”
  private int markedChar = UNMARKED;
  // “標(biāo)記”能標(biāo)記位置的最大長(zhǎng)度
  private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
  // skipLF(即skip Line Feed)是“是否忽略換行符”標(biāo)記
  private boolean skipLF = false;
  // 設(shè)置“標(biāo)記”時(shí),保存的skipLF的值
  private boolean markedSkipLF = false;
  // 默認(rèn)字符緩沖區(qū)大小
  private static int defaultCharBufferSize = 8192;
  // 默認(rèn)每一行的字符個(gè)數(shù)
  private static int defaultExpectedLineLength = 80;
  // 創(chuàng)建“Reader”對(duì)應(yīng)的BufferedReader對(duì)象,sz是BufferedReader的緩沖區(qū)大小
  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;
  }
 // 創(chuàng)建“Reader”對(duì)應(yīng)的BufferedReader對(duì)象,默認(rèn)的BufferedReader緩沖區(qū)大小是8k
  public BufferedReader(Reader in) {
   this(in, defaultCharBufferSize);
  }
  // 確?!癇ufferedReader”是打開狀態(tài)
  private void ensureOpen() throws IOException {
   if (in == null)
    throw new IOException("Stream closed");
  }
  // 填充緩沖區(qū)函數(shù)。有以下兩種情況被調(diào)用:
  // (01) 緩沖區(qū)沒有數(shù)據(jù)時(shí),通過fill()可以向緩沖區(qū)填充數(shù)據(jù)。
  // (02) 緩沖區(qū)數(shù)據(jù)被讀完,需更新時(shí),通過fill()可以更新緩沖區(qū)的數(shù)據(jù)。
  private void fill() throws IOException {
   // dst表示“cb中填充數(shù)據(jù)的起始位置”。
   int dst;
   if (markedChar <= UNMARKED) {
   // 沒有標(biāo)記的情況,則設(shè)dst=0。
    dst = 0;
   } else {
    // delta表示“當(dāng)前標(biāo)記的長(zhǎng)度”,它等于“下一個(gè)被讀取字符的位置”減去“標(biāo)記的位置”的差值;
    int delta = nextChar - markedChar;
    if (delta >= readAheadLimit) {
     // 若“當(dāng)前標(biāo)記的長(zhǎng)度”超過了“標(biāo)記上限(readAheadLimit)”,
     // 則丟棄標(biāo)記!
     markedChar = INVALIDATED;
     readAheadLimit = 0;
    dst = 0;
    } else {
     if (readAheadLimit <= cb.length) {
      // 若“當(dāng)前標(biāo)記的長(zhǎng)度”沒有超過了“標(biāo)記上限(readAheadLimit)”,
      // 并且“標(biāo)記上限(readAheadLimit)”小于/等于“緩沖的長(zhǎng)度”;
      // 則先將“下一個(gè)要被讀取的位置,距離我們標(biāo)記的置符的距離”間的字符保存到cb中。
     System.arraycopy(cb, markedChar, cb, 0, delta);
      markedChar = 0;
     dst = delta;
    } else {
     // 若“當(dāng)前標(biāo)記的長(zhǎng)度”沒有超過了“標(biāo)記上限(readAheadLimit)”,
     // 并且“標(biāo)記上限(readAheadLimit)”大于“緩沖的長(zhǎng)度”;
     // 則重新設(shè)置緩沖區(qū)大小,并將“下一個(gè)要被讀取的位置,距離我們標(biāo)記的置符的距離”間的字符保存到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”中讀取數(shù)據(jù),并存儲(chǔ)到字符數(shù)組cb中;
    // 從cb的dst位置開始存儲(chǔ),讀取的字符個(gè)數(shù)是cb.length - dst
    // n是實(shí)際讀取的字符個(gè)數(shù);若n==0(即一個(gè)也沒讀到),則繼續(xù)讀??!
    n = in.read(cb, dst, cb.length - dst);
   } while (n == 0);
   // 如果從“in”中讀到了數(shù)據(jù),則設(shè)置nChars(cb中字符的數(shù)目)=dst+n,
   // 并且nextChar(下一個(gè)被讀取的字符的位置)=dst。
   if (n > 0) {
    nChars = dst + n;
    nextChar = dst;
   }
  }
  // 從BufferedReader中讀取一個(gè)字符,該字符以int的方式返回
  public int read() throws IOException {
   synchronized (lock) {
    ensureOpen();
    for (;;) {
     // 若“緩沖區(qū)的數(shù)據(jù)已經(jīng)被讀完”,
     // 則先通過fill()更新緩沖區(qū)數(shù)據(jù)
     if (nextChar >= nChars) {
      fill();
      if (nextChar >= nChars)
       return -1;
     }
     // 若要“忽略換行符”,
     // 則對(duì)下一個(gè)字符是否是換行符進(jìn)行處理。
     if (skipLF) {
      skipLF = false;
      if (cb[nextChar] == '\n') {
       nextChar++;
       continue;
      }
     }
     // 返回下一個(gè)字符
     return cb[nextChar++];
    }
   }
  }
  // 將緩沖區(qū)中的數(shù)據(jù)寫入到數(shù)組cbuf中。off是數(shù)組cbuf中的寫入起始位置,len是寫入長(zhǎng)度
  private int read(char[] cbuf, int off, int len) throws IOException {
   // 若“緩沖區(qū)的數(shù)據(jù)已經(jīng)被讀完”,則更新緩沖區(qū)數(shù)據(jù)。
   if (nextChar >= nChars) {
    if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
     return in.read(cbuf, off, len);
    }
    fill();
   }
   // 若更新數(shù)據(jù)之后,沒有任何變化;則退出。
   if (nextChar >= nChars) return -;
   // 若要“忽略換行符”,則進(jìn)行相應(yīng)處理
   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;
  }
  // 對(duì)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;
   }
  }
  // 讀取一行數(shù)據(jù)。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);
    }
   }
  }
  // 讀取一行數(shù)據(jù)。不忽略換行符
  public String readLine() throws IOException {
   return readLine(false);
  }
  // 跳過n個(gè)字符
  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;
   }
  }
  // “下一個(gè)字符”是否可讀
  public boolean ready() throws IOException {
   synchronized (lock) {
    ensureOpen();
    // 若忽略換行符為true;
    // 則判斷下一個(gè)符號(hào)是否是換行符,若是的話,則忽略
    if (skipLF) {
     if (nextChar >= nChars && in.ready()) {
      fill();
     }
     if (nextChar < nChars) {
      if (cb[nextChar] == '\n')
       nextChar++;
      skipLF = false;
     }
    }
    return (nextChar < nChars) || in.ready();
   }
  }
  // 始終返回true。因?yàn)锽ufferedReader支持mark(), reset()
  public boolean markSupported() {
   return true;
  }
  // 標(biāo)記當(dāng)前BufferedReader的下一個(gè)要讀取位置。關(guān)于readAheadLimit的作用,參考后面的說明。
  public void mark(int readAheadLimit) throws IOException {
   if (readAheadLimit < 0) {
   throw new IllegalArgumentException("Read-ahead limit < 0");
   }
   synchronized (lock) {
    ensureOpen();
    // 設(shè)置readAheadLimit
    this.readAheadLimit = readAheadLimit;
    // 保存下一個(gè)要讀取的位置
    markedChar = nextChar;
    // 保存“是否忽略換行符”標(biāo)記
    markedSkipLF = skipLF;
   }
  }
  // 重置BufferedReader的下一個(gè)要讀取位置,
  // 將其還原到mark()中所保存的位置。
  public void reset() throws IOException {
   synchronized (lock) {
    ensureOpen();
   if (markedChar < 0)
     throw new IOException((markedChar == INVALIDATED)
          &#63; "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提供緩沖功能。創(chuàng)建BufferReader時(shí),我們會(huì)通過它的構(gòu)造函數(shù)指定某個(gè)Reader為參數(shù)。BufferReader會(huì)將該Reader中的數(shù)據(jù)分批讀取,每次讀取一部分到緩沖中;操作完緩沖中的這部分?jǐn)?shù)據(jù)之后,再?gòu)腞eader中讀取下一部分的數(shù)據(jù)。

為什么需要緩沖呢?原因很簡(jiǎn)單,效率問題!緩沖中的數(shù)據(jù)實(shí)際上是保存在內(nèi)存中,而原始數(shù)據(jù)可能是保存在硬盤或NandFlash中;而我們知道,從內(nèi)存中讀取數(shù)據(jù)的速度比從硬盤讀取數(shù)據(jù)的速度至少快10倍以上。

那干嘛不干脆一次性將全部數(shù)據(jù)都讀取到緩沖中呢?第一,讀取全部的數(shù)據(jù)所需要的時(shí)間可能會(huì)很長(zhǎng)。第二,內(nèi)存價(jià)格很貴,容量不想硬盤那么大。

下面,我就BufferReader中最重要的函數(shù)fill()進(jìn)行說明。其它的函數(shù)很容易理解,我就不詳細(xì)介紹了,大家可以參考源碼中的注釋進(jìn)行理解。我們先看看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;
  }
 }

根據(jù)fill()中的if...else...,我將fill()分為4種情況進(jìn)行說明。 

情況1:讀取完緩沖區(qū)的數(shù)據(jù),并且緩沖區(qū)沒有被標(biāo)記

執(zhí)行流程如下,

(01) 其它函數(shù)調(diào)用 fill(),來更新緩沖區(qū)的數(shù)據(jù)

(02) fill() 執(zhí)行代碼 if (markedChar <= UNMARKED) { ... }

為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼: 

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

說明:

這種情況發(fā)生的情況是 — — Reader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖中進(jìn)行操作。每次當(dāng)我們讀取完緩沖中的數(shù)據(jù)之后,并且此時(shí)BufferedReader沒有被標(biāo)記;那么,就接著從Reader(BufferReader提供緩沖功能的Reader)中讀取下一部分的數(shù)據(jù)到緩沖中。

其中,判斷是否讀完緩沖區(qū)中的數(shù)據(jù),是通過“比較nextChar和nChars之間大小”來判斷的。其中,nChars 是緩沖區(qū)中字符的總的個(gè)數(shù),而 nextChar 是緩沖區(qū)中下一個(gè)要讀取的字符的位置。

判斷BufferedReader有沒有被標(biāo)記,是通過“markedChar”來判斷的。

理解這個(gè)思想之后,我們?cè)賹?duì)這種情況下的fill()的代碼進(jìn)行分析,就特別容易理解了。

(01) if (markedChar <= UNMARKED) 它的作用是判斷“BufferedReader是否被標(biāo)記”。若被標(biāo)記,則dst=0。

(02) in.read(cb, dst, cb.length - dst) 等價(jià)于 in.read(cb, 0, cb.length),意思是從Reader對(duì)象in中讀取cb.length個(gè)數(shù)據(jù),并存儲(chǔ)到緩沖區(qū)cb中,而且從緩沖區(qū)cb的位置0開始存儲(chǔ)。該函數(shù)返回值等于n,也就是n表示實(shí)際讀取的字符個(gè)數(shù)。若n=0(即沒有讀取到數(shù)據(jù)),則繼續(xù)讀取,直到讀到數(shù)據(jù)為止。

(03) nChars=dst+n 等價(jià)于 nChars=n;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nChars(緩沖區(qū)的數(shù)據(jù)個(gè)數(shù))為n。

(04) nextChar=dst 等價(jià)于 nextChar=0;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nextChar(緩沖區(qū)中下一個(gè)會(huì)被讀取的字符的索引值)為0。

情況2:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,并且“當(dāng)前標(biāo)記的長(zhǎng)度”超過“標(biāo)記上限(readAheadLimit)”

執(zhí)行流程如下,

(01) 其它函數(shù)調(diào)用 fill(),來更新緩沖區(qū)的數(shù)據(jù)

(02) fill() 執(zhí)行代碼 if (delta >= readAheadLimit) { ... }

為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼: 

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

說明:

這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”大于“標(biāo)記上限”;那么,就發(fā)生情況2。此時(shí),我們會(huì)丟棄“標(biāo)記”并更新緩沖區(qū)。

(01) delta = nextChar - markedChar;其中,delta就是“當(dāng)前標(biāo)記的長(zhǎng)度”,它是“下一個(gè)被讀取字符的位置”減去“被標(biāo)記的位置”的差值。

(02) if (delta >= readAheadLimit);其中,當(dāng)delta >= readAheadLimit,就意味著,“當(dāng)前標(biāo)記的長(zhǎng)度”>=“標(biāo)記上限”。為什么要有標(biāo)記上限,即readAheadLimit的值到底有何意義呢?

我們標(biāo)記一個(gè)位置之后,更新緩沖區(qū)的時(shí)候,被標(biāo)記的位置會(huì)被保存;當(dāng)我們不停的更新緩沖區(qū)的時(shí)候,被標(biāo)記的位置會(huì)被不停的放大。然后內(nèi)存的容量是有效的,我們不可能不限制長(zhǎng)度的存儲(chǔ)標(biāo)記。所以,需要readAheadLimit來限制標(biāo)記長(zhǎng)度!

(03) in.read(cb, dst, cb.length - dst) 等價(jià)于 in.read(cb, 0, cb.length),意思是從Reader對(duì)象in中讀取cb.length個(gè)數(shù)據(jù),并存儲(chǔ)到緩沖區(qū)cb中,而且從緩沖區(qū)cb的位置0開始存儲(chǔ)。該函數(shù)返回值等于n,也就是n表示實(shí)際讀取的字符個(gè)數(shù)。若n=0(即沒有讀取到數(shù)據(jù)),則繼續(xù)讀取,直到讀到數(shù)據(jù)為止。

(04) nChars=dst+n 等價(jià)于 nChars=n;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nChars(緩沖區(qū)的數(shù)據(jù)個(gè)數(shù))為n。

(05) nextChar=dst 等價(jià)于 nextChar=0;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nextChar(緩沖區(qū)中下一個(gè)會(huì)被讀取的字符的索引值)為0。 

情況3:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,“當(dāng)前標(biāo)記的長(zhǎng)度”沒超過“標(biāo)記上限(readAheadLimit)”,并且“標(biāo)記上限(readAheadLimit)”小于/等于“緩沖的長(zhǎng)度”;
執(zhí)行流程如下,

(01) 其它函數(shù)調(diào)用 fill(),來更新緩沖區(qū)的數(shù)據(jù)

(02) fill() 執(zhí)行代碼 if (readAheadLimit <= cb.length) { ... }

為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼: 

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

說明:

這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”小于“標(biāo)記上限”,并且“標(biāo)記上限”小于/等于“緩沖區(qū)長(zhǎng)度”;那么,就發(fā)生情況3。此時(shí),我們保留“被標(biāo)記的位置”(即,保留被標(biāo)記位置開始的數(shù)據(jù)),并更新緩沖區(qū)(將新增的數(shù)據(jù),追加到保留的數(shù)據(jù)之后)。 

情況4:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,“當(dāng)前標(biāo)記的長(zhǎng)度”沒超過“標(biāo)記上限(readAheadLimit)”,并且“標(biāo)記上限(readAheadLimit)”大于“緩沖的長(zhǎng)度”;

執(zhí)行流程如下,

(01) 其它函數(shù)調(diào)用 fill(),來更新緩沖區(qū)的數(shù)據(jù)

(02) fill() 執(zhí)行代碼 else { char ncb[] = new char[readAheadLimit]; ... }

為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼:

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

 說明:

這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”小于“標(biāo)記上限”,并且“標(biāo)記上限”大于“緩沖區(qū)長(zhǎng)度”;那么,就發(fā)生情況4。此時(shí),我們要先更新緩沖區(qū)的大小,然后再保留“被標(biāo)記的位置”(即,保留被標(biāo)記位置開始的數(shù)據(jù)),并更新緩沖區(qū)數(shù)據(jù)(將新增的數(shù)據(jù),追加到保留的數(shù)據(jù)之后)。 

示例代碼

關(guān)于BufferedReader中API的詳細(xì)用法,參考示例代碼(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 測(cè)試程序
 *
 * 
 */
 public class BufferedReaderTest {
  private static final int LEN = 5;
  public static void main(String[] args) {
   testBufferedReader() ;
  }
  /**
  * BufferedReader的API測(cè)試函數(shù)
  */
  private static void testBufferedReader() {
   // 創(chuàng)建BufferedReader字符流,內(nèi)容是ArrayLetters數(shù)組
   try {
    File file = new File("bufferedreader.txt");
    BufferedReader in =
     new BufferedReader(
      new FileReader(file));
    // 從字符流中讀取5個(gè)字符?!癮bcde”
   for (int i=0; i<LEN; i++) {
     // 若能繼續(xù)讀取下一個(gè)字符,則讀取下一個(gè)字符
     if (in.ready()) {
      // 讀取“字符流的下一個(gè)字符”
      int tmp = in.read();
      System.out.printf("%d : %c\n", i, tmp);
     }
    }
    // 若“該字符流”不支持標(biāo)記功能,則直接退出
    if (!in.markSupported()) {
     System.out.println("make not supported!");
     return ;
    }
    // 標(biāo)記“當(dāng)前索引位置”,即標(biāo)記第6個(gè)位置的元素--“f”
   // 1024對(duì)應(yīng)marklimit
    in.mark(1024);
   // 跳過22個(gè)字符。
    in.skip(22);
    // 讀取5個(gè)字符
    char[] buf = new char[LEN];
   in.read(buf, 0, LEN);
    System.out.printf("buf=%s\n", String.valueOf(buf));
    // 讀取該行剩余的數(shù)據(jù)
    System.out.printf("readLine=%s\n", in.readLine());
    // 重置“輸入流的索引”為mark()所標(biāo)記的位置,即重置到“f”處。
    in.reset();
   // 從“重置后的字符流”中讀取5個(gè)字符到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的內(nèi)容如下:

abcdefghijklmnopqrstuvwxyz
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ

運(yùn)行結(jié)果:

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

上述就是小編為大家分享的 BufferedReader如何在Java項(xiàng)目中使用了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI