java io系列23之 BufferedReader(字符緩沖輸入流)


轉載請注明出處: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 }
View Code

說明
要想讀懂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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM