轉載請注明出處:http://www.cnblogs.com/skywang12345/p/io_23.html
更多內容請參考:java io系列01之 "目錄"
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)

1 package java.io; 2 3 public class BufferedReader extends Reader { 4 5 private Reader in; 6 7 // 字符緩沖區 8 private char cb[]; 9 // nChars 是cb緩沖區中字符的總的個數 10 // nextChar 是下一個要讀取的字符在cb緩沖區中的位置 11 private int nChars, nextChar; 12 13 // 表示“標記無效”。它與UNMARKED的區別是: 14 // (01) UNMARKED 是壓根就沒有設置過標記。 15 // (02) 而INVALIDATED是設置了標記,但是被標記位置太長,導致標記無效! 16 private static final int INVALIDATED = -2; 17 // 表示沒有設置“標記” 18 private static final int UNMARKED = -1; 19 // “標記” 20 private int markedChar = UNMARKED; 21 // “標記”能標記位置的最大長度 22 private int readAheadLimit = 0; /* Valid only when markedChar > 0 */ 23 24 // skipLF(即skip Line Feed)是“是否忽略換行符”標記 25 private boolean skipLF = false; 26 27 // 設置“標記”時,保存的skipLF的值 28 private boolean markedSkipLF = false; 29 30 // 默認字符緩沖區大小 31 private static int defaultCharBufferSize = 8192; 32 // 默認每一行的字符個數 33 private static int defaultExpectedLineLength = 80; 34 35 // 創建“Reader”對應的BufferedReader對象,sz是BufferedReader的緩沖區大小 36 public BufferedReader(Reader in, int sz) { 37 super(in); 38 if (sz <= 0) 39 throw new IllegalArgumentException("Buffer size <= 0"); 40 this.in = in; 41 cb = new char[sz]; 42 nextChar = nChars = 0; 43 } 44 45 // 創建“Reader”對應的BufferedReader對象,默認的BufferedReader緩沖區大小是8k 46 public BufferedReader(Reader in) { 47 this(in, defaultCharBufferSize); 48 } 49 50 // 確保“BufferedReader”是打開狀態 51 private void ensureOpen() throws IOException { 52 if (in == null) 53 throw new IOException("Stream closed"); 54 } 55 56 // 填充緩沖區函數。有以下兩種情況被調用: 57 // (01) 緩沖區沒有數據時,通過fill()可以向緩沖區填充數據。 58 // (02) 緩沖區數據被讀完,需更新時,通過fill()可以更新緩沖區的數據。 59 private void fill() throws IOException { 60 // dst表示“cb中填充數據的起始位置”。 61 int dst; 62 if (markedChar <= UNMARKED) { 63 // 沒有標記的情況,則設dst=0。 64 dst = 0; 65 } else { 66 // delta表示“當前標記的長度”,它等於“下一個被讀取字符的位置”減去“標記的位置”的差值; 67 int delta = nextChar - markedChar; 68 if (delta >= readAheadLimit) { 69 // 若“當前標記的長度”超過了“標記上限(readAheadLimit)”, 70 // 則丟棄標記! 71 markedChar = INVALIDATED; 72 readAheadLimit = 0; 73 dst = 0; 74 } else { 75 if (readAheadLimit <= cb.length) { 76 // 若“當前標記的長度”沒有超過了“標記上限(readAheadLimit)”, 77 // 並且“標記上限(readAheadLimit)”小於/等於“緩沖的長度”; 78 // 則先將“下一個要被讀取的位置,距離我們標記的置符的距離”間的字符保存到cb中。 79 System.arraycopy(cb, markedChar, cb, 0, delta); 80 markedChar = 0; 81 dst = delta; 82 } else { 83 // 若“當前標記的長度”沒有超過了“標記上限(readAheadLimit)”, 84 // 並且“標記上限(readAheadLimit)”大於“緩沖的長度”; 85 // 則重新設置緩沖區大小,並將“下一個要被讀取的位置,距離我們標記的置符的距離”間的字符保存到cb中。 86 char ncb[] = new char[readAheadLimit]; 87 System.arraycopy(cb, markedChar, ncb, 0, delta); 88 cb = ncb; 89 markedChar = 0; 90 dst = delta; 91 } 92 // 更新nextChar和nChars 93 nextChar = nChars = delta; 94 } 95 } 96 97 int n; 98 do { 99 // 從“in”中讀取數據,並存儲到字符數組cb中; 100 // 從cb的dst位置開始存儲,讀取的字符個數是cb.length - dst 101 // n是實際讀取的字符個數;若n==0(即一個也沒讀到),則繼續讀取! 102 n = in.read(cb, dst, cb.length - dst); 103 } while (n == 0); 104 105 // 如果從“in”中讀到了數據,則設置nChars(cb中字符的數目)=dst+n, 106 // 並且nextChar(下一個被讀取的字符的位置)=dst。 107 if (n > 0) { 108 nChars = dst + n; 109 nextChar = dst; 110 } 111 } 112 113 // 從BufferedReader中讀取一個字符,該字符以int的方式返回 114 public int read() throws IOException { 115 synchronized (lock) { 116 ensureOpen(); 117 for (;;) { 118 // 若“緩沖區的數據已經被讀完”, 119 // 則先通過fill()更新緩沖區數據 120 if (nextChar >= nChars) { 121 fill(); 122 if (nextChar >= nChars) 123 return -1; 124 } 125 // 若要“忽略換行符”, 126 // 則對下一個字符是否是換行符進行處理。 127 if (skipLF) { 128 skipLF = false; 129 if (cb[nextChar] == '\n') { 130 nextChar++; 131 continue; 132 } 133 } 134 // 返回下一個字符 135 return cb[nextChar++]; 136 } 137 } 138 } 139 140 // 將緩沖區中的數據寫入到數組cbuf中。off是數組cbuf中的寫入起始位置,len是寫入長度 141 private int read1(char[] cbuf, int off, int len) throws IOException { 142 // 若“緩沖區的數據已經被讀完”,則更新緩沖區數據。 143 if (nextChar >= nChars) { 144 if (len >= cb.length && markedChar <= UNMARKED && !skipLF) { 145 return in.read(cbuf, off, len); 146 } 147 fill(); 148 } 149 // 若更新數據之后,沒有任何變化;則退出。 150 if (nextChar >= nChars) return -1; 151 // 若要“忽略換行符”,則進行相應處理 152 if (skipLF) { 153 skipLF = false; 154 if (cb[nextChar] == '\n') { 155 nextChar++; 156 if (nextChar >= nChars) 157 fill(); 158 if (nextChar >= nChars) 159 return -1; 160 } 161 } 162 // 拷貝字符操作 163 int n = Math.min(len, nChars - nextChar); 164 System.arraycopy(cb, nextChar, cbuf, off, n); 165 nextChar += n; 166 return n; 167 } 168 169 // 對read1()的封裝,添加了“同步處理”和“阻塞式讀取”等功能 170 public int read(char cbuf[], int off, int len) throws IOException { 171 synchronized (lock) { 172 ensureOpen(); 173 if ((off < 0) || (off > cbuf.length) || (len < 0) || 174 ((off + len) > cbuf.length) || ((off + len) < 0)) { 175 throw new IndexOutOfBoundsException(); 176 } else if (len == 0) { 177 return 0; 178 } 179 180 int n = read1(cbuf, off, len); 181 if (n <= 0) return n; 182 while ((n < len) && in.ready()) { 183 int n1 = read1(cbuf, off + n, len - n); 184 if (n1 <= 0) break; 185 n += n1; 186 } 187 return n; 188 } 189 } 190 191 // 讀取一行數據。ignoreLF是“是否忽略換行符” 192 String readLine(boolean ignoreLF) throws IOException { 193 StringBuffer s = null; 194 int startChar; 195 196 synchronized (lock) { 197 ensureOpen(); 198 boolean omitLF = ignoreLF || skipLF; 199 200 bufferLoop: 201 for (;;) { 202 203 if (nextChar >= nChars) 204 fill(); 205 if (nextChar >= nChars) { /* EOF */ 206 if (s != null && s.length() > 0) 207 return s.toString(); 208 else 209 return null; 210 } 211 boolean eol = false; 212 char c = 0; 213 int i; 214 215 /* Skip a leftover '\n', if necessary */ 216 if (omitLF && (cb[nextChar] == '\n')) 217 nextChar++; 218 skipLF = false; 219 omitLF = false; 220 221 charLoop: 222 for (i = nextChar; i < nChars; i++) { 223 c = cb[i]; 224 if ((c == '\n') || (c == '\r')) { 225 eol = true; 226 break charLoop; 227 } 228 } 229 230 startChar = nextChar; 231 nextChar = i; 232 233 if (eol) { 234 String str; 235 if (s == null) { 236 str = new String(cb, startChar, i - startChar); 237 } else { 238 s.append(cb, startChar, i - startChar); 239 str = s.toString(); 240 } 241 nextChar++; 242 if (c == '\r') { 243 skipLF = true; 244 } 245 return str; 246 } 247 248 if (s == null) 249 s = new StringBuffer(defaultExpectedLineLength); 250 s.append(cb, startChar, i - startChar); 251 } 252 } 253 } 254 255 // 讀取一行數據。不忽略換行符 256 public String readLine() throws IOException { 257 return readLine(false); 258 } 259 260 // 跳過n個字符 261 public long skip(long n) throws IOException { 262 if (n < 0L) { 263 throw new IllegalArgumentException("skip value is negative"); 264 } 265 synchronized (lock) { 266 ensureOpen(); 267 long r = n; 268 while (r > 0) { 269 if (nextChar >= nChars) 270 fill(); 271 if (nextChar >= nChars) /* EOF */ 272 break; 273 if (skipLF) { 274 skipLF = false; 275 if (cb[nextChar] == '\n') { 276 nextChar++; 277 } 278 } 279 long d = nChars - nextChar; 280 if (r <= d) { 281 nextChar += r; 282 r = 0; 283 break; 284 } 285 else { 286 r -= d; 287 nextChar = nChars; 288 } 289 } 290 return n - r; 291 } 292 } 293 294 // “下一個字符”是否可讀 295 public boolean ready() throws IOException { 296 synchronized (lock) { 297 ensureOpen(); 298 299 // 若忽略換行符為true; 300 // 則判斷下一個符號是否是換行符,若是的話,則忽略 301 if (skipLF) { 302 if (nextChar >= nChars && in.ready()) { 303 fill(); 304 } 305 if (nextChar < nChars) { 306 if (cb[nextChar] == '\n') 307 nextChar++; 308 skipLF = false; 309 } 310 } 311 return (nextChar < nChars) || in.ready(); 312 } 313 } 314 315 // 始終返回true。因為BufferedReader支持mark(), reset() 316 public boolean markSupported() { 317 return true; 318 } 319 320 // 標記當前BufferedReader的下一個要讀取位置。關於readAheadLimit的作用,參考后面的說明。 321 public void mark(int readAheadLimit) throws IOException { 322 if (readAheadLimit < 0) { 323 throw new IllegalArgumentException("Read-ahead limit < 0"); 324 } 325 synchronized (lock) { 326 ensureOpen(); 327 // 設置readAheadLimit 328 this.readAheadLimit = readAheadLimit; 329 // 保存下一個要讀取的位置 330 markedChar = nextChar; 331 // 保存“是否忽略換行符”標記 332 markedSkipLF = skipLF; 333 } 334 } 335 336 // 重置BufferedReader的下一個要讀取位置, 337 // 將其還原到mark()中所保存的位置。 338 public void reset() throws IOException { 339 synchronized (lock) { 340 ensureOpen(); 341 if (markedChar < 0) 342 throw new IOException((markedChar == INVALIDATED) 343 ? "Mark invalid" 344 : "Stream not marked"); 345 nextChar = markedChar; 346 skipLF = markedSkipLF; 347 } 348 } 349 350 public void close() throws IOException { 351 synchronized (lock) { 352 if (in == null) 353 return; 354 in.close(); 355 in = null; 356 cb = null; 357 } 358 } 359 }
說明:
要想讀懂BufferReader的源碼,就要先理解它的思想。BufferReader的作用是為其它Reader提供緩沖功能。創建BufferReader時,我們會通過它的構造函數指定某個Reader為參數。BufferReader會將該Reader中的數據分批讀取,每次讀取一部分到緩沖中;操作完緩沖中的這部分數據之后,再從Reader中讀取下一部分的數據。
為什么需要緩沖呢?原因很簡單,效率問題!緩沖中的數據實際上是保存在內存中,而原始數據可能是保存在硬盤或NandFlash中;而我們知道,從內存中讀取數據的速度比從硬盤讀取數據的速度至少快10倍以上。
那干嘛不干脆一次性將全部數據都讀取到緩沖中呢?第一,讀取全部的數據所需要的時間可能會很長。第二,內存價格很貴,容量不想硬盤那么大。
下面,我就BufferReader中最重要的函數fill()進行說明。其它的函數很容易理解,我就不詳細介紹了,大家可以參考源碼中的注釋進行理解。我們先看看fill()的源碼:
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar <= UNMARKED) { 4 /* No mark */ 5 dst = 0; 6 } else { 7 /* Marked */ 8 int delta = nextChar - markedChar; 9 if (delta >= readAheadLimit) { 10 /* Gone past read-ahead limit: Invalidate mark */ 11 markedChar = INVALIDATED; 12 readAheadLimit = 0; 13 dst = 0; 14 } else { 15 if (readAheadLimit <= cb.length) { 16 /* Shuffle in the current buffer */ 17 System.arraycopy(cb, markedChar, cb, 0, delta); 18 markedChar = 0; 19 dst = delta; 20 } else { 21 /* Reallocate buffer to accommodate read-ahead limit */ 22 char ncb[] = new char[readAheadLimit]; 23 System.arraycopy(cb, markedChar, ncb, 0, delta); 24 cb = ncb; 25 markedChar = 0; 26 dst = delta; 27 } 28 nextChar = nChars = delta; 29 } 30 } 31 32 int n; 33 do { 34 n = in.read(cb, dst, cb.length - dst); 35 } while (n == 0); 36 if (n > 0) { 37 nChars = dst + n; 38 nextChar = dst; 39 } 40 }
根據fill()中的if...else...,我將fill()分為4種情況進行說明。
情況1:讀取完緩沖區的數據,並且緩沖區沒有被標記
執行流程如下,
(01) 其它函數調用 fill(),來更新緩沖區的數據
(02) fill() 執行代碼 if (markedChar <= UNMARKED) { ... }
為了方便分析,我們將這種情況下fill()執行的操作等價於以下代碼:
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar <= UNMARKED) { 4 /* No mark */ 5 dst = 0; 6 } 7 8 int n; 9 do { 10 n = in.read(cb, dst, cb.length - dst); 11 } while (n == 0); 12 13 if (n > 0) { 14 nChars = dst + n; 15 nextChar = dst; 16 } 17 }
說明:
這種情況發生的情況是 — — 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()執行的操作等價於以下代碼:
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar > UNMARKED) { 4 int delta = nextChar - markedChar; 5 if (delta >= readAheadLimit) { 6 markedChar = INVALIDATED; 7 readAheadLimit = 0; 8 dst = 0; 9 } 10 } 11 12 int n; 13 do { 14 n = in.read(cb, dst, cb.length - dst); 15 } while (n == 0); 16 if (n > 0) { 17 nChars = dst + n; 18 nextChar = dst; 19 } 20 }
說明:
這種情況發生的情況是 — — 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()執行的操作等價於以下代碼:
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar > UNMARKED) { 4 int delta = nextChar - markedChar; 5 if ((delta < readAheadLimit) && (readAheadLimit <= cb.length) ) { 6 System.arraycopy(cb, markedChar, cb, 0, delta); 7 markedChar = 0; 8 dst = delta; 9 10 nextChar = nChars = delta; 11 } 12 } 13 14 int n; 15 do { 16 n = in.read(cb, dst, cb.length - dst); 17 } while (n == 0); 18 if (n > 0) { 19 nChars = dst + n; 20 nextChar = dst; 21 } 22 }
說明:
這種情況發生的情況是 — — BufferedReader中有很長的數據,我們每次從中讀取一部分數據到緩沖區中進行操作。當我們讀取完緩沖區中的數據之后,並且此時,BufferedReader存在標記時,同時,“當前標記的長度”小於“標記上限”,並且“標記上限”小於/等於“緩沖區長度”;那么,就發生情況3。此時,我們保留“被標記的位置”(即,保留被標記位置開始的數據),並更新緩沖區(將新增的數據,追加到保留的數據之后)。
情況4:讀取完緩沖區的數據,緩沖區的標記位置>0,“當前標記的長度”沒超過“標記上限(readAheadLimit)”,並且“標記上限(readAheadLimit)”大於“緩沖的長度”;
執行流程如下,
(01) 其它函數調用 fill(),來更新緩沖區的數據
(02) fill() 執行代碼 else { char ncb[] = new char[readAheadLimit]; ... }
為了方便分析,我們將這種情況下fill()執行的操作等價於以下代碼:
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar > UNMARKED) { 4 int delta = nextChar - markedChar; 5 if ((delta < readAheadLimit) && (readAheadLimit > cb.length) ) { 6 char ncb[] = new char[readAheadLimit]; 7 System.arraycopy(cb, markedChar, ncb, 0, delta); 8 cb = ncb; 9 markedChar = 0; 10 dst = delta; 11 12 nextChar = nChars = delta; 13 } 14 } 15 16 int n; 17 do { 18 n = in.read(cb, dst, cb.length - dst); 19 } while (n == 0); 20 if (n > 0) { 21 nChars = dst + n; 22 nextChar = dst; 23 } 24 }
說明:
這種情況發生的情況是 — — BufferedReader中有很長的數據,我們每次從中讀取一部分數據到緩沖區中進行操作。當我們讀取完緩沖區中的數據之后,並且此時,BufferedReader存在標記時,同時,“當前標記的長度”小於“標記上限”,並且“標記上限”大於“緩沖區長度”;那么,就發生情況4。此時,我們要先更新緩沖區的大小,然后再保留“被標記的位置”(即,保留被標記位置開始的數據),並更新緩沖區數據(將新增的數據,追加到保留的數據之后)。
示例代碼
關於BufferedReader中API的詳細用法,參考示例代碼(BufferedReaderTest.java):
1 import java.io.BufferedReader; 2 import java.io.ByteArrayInputStream; 3 import java.io.File; 4 import java.io.InputStream; 5 import java.io.FileReader; 6 import java.io.IOException; 7 import java.io.FileNotFoundException; 8 import java.lang.SecurityException; 9 10 /** 11 * BufferedReader 測試程序 12 * 13 * @author skywang 14 */ 15 public class BufferedReaderTest { 16 17 private static final int LEN = 5; 18 19 public static void main(String[] args) { 20 testBufferedReader() ; 21 } 22 23 /** 24 * BufferedReader的API測試函數 25 */ 26 private static void testBufferedReader() { 27 28 // 創建BufferedReader字符流,內容是ArrayLetters數組 29 try { 30 File file = new File("bufferedreader.txt"); 31 BufferedReader in = 32 new BufferedReader( 33 new FileReader(file)); 34 35 // 從字符流中讀取5個字符。“abcde” 36 for (int i=0; i<LEN; i++) { 37 // 若能繼續讀取下一個字符,則讀取下一個字符 38 if (in.ready()) { 39 // 讀取“字符流的下一個字符” 40 int tmp = in.read(); 41 System.out.printf("%d : %c\n", i, tmp); 42 } 43 } 44 45 // 若“該字符流”不支持標記功能,則直接退出 46 if (!in.markSupported()) { 47 System.out.println("make not supported!"); 48 return ; 49 } 50 51 // 標記“當前索引位置”,即標記第6個位置的元素--“f” 52 // 1024對應marklimit 53 in.mark(1024); 54 55 // 跳過22個字符。 56 in.skip(22); 57 58 // 讀取5個字符 59 char[] buf = new char[LEN]; 60 in.read(buf, 0, LEN); 61 System.out.printf("buf=%s\n", String.valueOf(buf)); 62 // 讀取該行剩余的數據 63 System.out.printf("readLine=%s\n", in.readLine()); 64 65 // 重置“輸入流的索引”為mark()所標記的位置,即重置到“f”處。 66 in.reset(); 67 // 從“重置后的字符流”中讀取5個字符到buf中。即讀取“fghij” 68 in.read(buf, 0, LEN); 69 System.out.printf("buf=%s\n", String.valueOf(buf)); 70 71 in.close(); 72 } catch (FileNotFoundException e) { 73 e.printStackTrace(); 74 } catch (SecurityException e) { 75 e.printStackTrace(); 76 } catch (IOException e) { 77 e.printStackTrace(); 78 } 79 } 80 }
程序中讀取的bufferedreader.txt的內容如下:
abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ
運行結果:
0 : a
1 : b
2 : c
3 : d
4 : e
buf=01234
readLine=56789
buf=fghij