-
Notifications
You must be signed in to change notification settings - Fork 668
/
LineNumberInputStream.java
358 lines (317 loc) · 14.1 KB
/
LineNumberInputStream.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.io;
/**
* This class is an input stream filter that provides the added
* functionality of keeping track of the current line number.
* <p>
* A line is a sequence of bytes ending with a carriage return
* character ({@code '\u005Cr'}), a newline character
* ({@code '\u005Cn'}), or a carriage return character followed
* immediately by a linefeed character. In all three cases, the line
* terminating character(s) are returned as a single newline character.
* <p>
* The line number begins at {@code 0}, and is incremented by
* {@code 1} when a {@code read} returns a newline character.
*
* @author Arthur van Hoff
* @see java.io.LineNumberReader
* @since 1.0
* @deprecated This class incorrectly assumes that bytes adequately represent
* characters. As of JDK 1.1, the preferred way to operate on
* character streams is via the new character-stream classes, which
* include a class for counting line numbers.
*/
/*
* 带行号的输入流
*
* 在读取数据时,会记录当前"读游标"所在的行。
*
* 过时原因:该类在设计之初用来读取字符流,并假设"字节"可以表示所有字符,
* 但现实是字符由多字节表示,所以使用LineNumberReader来替代了此类。
*/
@Deprecated
public class LineNumberInputStream extends FilterInputStream {
int pushBack = -1; // 缓存标记,临时存储\r后面的一个字节
int lineNumber; // 行号
int markLineNumber; // 行号存档
int markPushBack = -1; // 缓存标记存档
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Constructs a newline number input stream that reads its input
* from the specified input stream.
*
* @param in the underlying input stream.
*/
public LineNumberInputStream(InputStream in) {
super(in);
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 读 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an {@code int} in the range
* {@code 0} to {@code 255}. If no byte is available
* because the end of the stream has been reached, the value
* {@code -1} is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* The {@code read} method of
* {@code LineNumberInputStream} calls the {@code read}
* method of the underlying input stream. It checks for carriage
* returns and newline characters in the input, and modifies the
* current line number as appropriate. A carriage-return character or
* a carriage return followed by a newline character are both
* converted into a single newline character.
*
* @return the next byte of data, or {@code -1} if the end of this
* stream is reached.
*
* @throws IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
* @see java.io.LineNumberInputStream#getLineNumber()
*/
/*
* 尝试从当前输入流读取一个字节,读取成功直接返回,读取失败返回-1
*/
@SuppressWarnings("fallthrough")
public int read() throws IOException {
int c = pushBack;
// 如果没有缓存的字节,则直接从流中读取新的字节
if(c == -1) {
c = in.read();
} else {
// 重置缓存标记为-1
pushBack = -1;
}
switch(c) {
// 如果遇到了\r,则需要进一步读取下一个字节
case '\r':
pushBack = in.read();
// 如果\r后面紧跟着\n,说明遇到了\r\n组成的行结束标记
if(pushBack == '\n') {
pushBack = -1;
}
case '\n':
// 不论遇到\r还是\n还是\r\n,都需要将行号增一
lineNumber++;
return '\n';
}
return c;
}
/**
* Reads up to {@code len} bytes of data from this input stream
* into an array of bytes. This method blocks until some input is available.
* <p>
* The {@code read} method of
* {@code LineNumberInputStream} repeatedly calls the
* {@code read} method of zero arguments to fill in the byte array.
*
* @param b the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
*
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end of
* this stream has been reached.
*
* @throws IOException if an I/O error occurs.
* @see java.io.LineNumberInputStream#read()
*/
/*
* 尝试从当前输入流读取len个字节,并将读到的内容插入到字节数组b的off索引处
* 返回值表示成功读取的字节数量(可能小于预期值),返回-1表示已经没有可读内容了
*/
public int read(byte[] b, int off, int len) throws IOException {
if(b == null) {
throw new NullPointerException();
} else if((off<0) || (off>b.length) || (len<0) || ((off + len)>b.length) || ((off + len)<0)) {
throw new IndexOutOfBoundsException();
} else if(len == 0) {
return 0;
}
// 先尝试读取一个字节
int c = read();
if(c == -1) {
return -1;
}
b[off] = (byte) c;
int i = 1;
try {
// 循环读取,直到读够len个字节,或者遇到结束标记
for(; i<len; i++) {
c = read();
if(c == -1) {
break;
}
if(b != null) {
b[off + i] = (byte) c;
}
}
} catch(IOException ee) {
}
return i;
}
/*▲ 读 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 存档 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Marks the current position in this input stream. A subsequent
* call to the {@code reset} method repositions this stream at
* the last marked position so that subsequent reads re-read the same bytes.
* <p>
* The {@code mark} method of
* {@code LineNumberInputStream} remembers the current line
* number in a private variable, and then calls the {@code mark}
* method of the underlying input stream.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
*
* @see java.io.FilterInputStream#in
* @see java.io.LineNumberInputStream#reset()
*/
// 设置存档标记,readlimit是存档上限
public void mark(int readlimit) {
markLineNumber = lineNumber;
markPushBack = pushBack;
in.mark(readlimit);
}
/**
* Repositions this stream to the position at the time the
* {@code mark} method was last called on this input stream.
* <p>
* The {@code reset} method of
* {@code LineNumberInputStream} resets the line number to be
* the line number at the time the {@code mark} method was
* called, and then calls the {@code reset} method of the
* underlying input stream.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parser, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails,
* which, if it happens within readlimit bytes, allows the outer
* code to reset the stream and try another parser.
*
* @throws IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
* @see java.io.LineNumberInputStream#mark(int)
*/
// 重置"读游标"到存档区的起始位置
public void reset() throws IOException {
lineNumber = markLineNumber;
pushBack = markPushBack;
in.reset();
}
/*▲ 存档 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 杂项 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns the number of bytes that can be read from this input
* stream without blocking.
* <p>
* Note that if the underlying input stream is able to supply
* <i>k</i> input characters without blocking, the
* {@code LineNumberInputStream} can guarantee only to provide
* <i>k</i>/2 characters without blocking, because the
* <i>k</i> characters from the underlying input stream might
* consist of <i>k</i>/2 pairs of {@code '\u005Cr'} and
* {@code '\u005Cn'}, which are converted to just
* <i>k</i>/2 {@code '\u005Cn'} characters.
*
* @return the number of bytes that can be read from this input stream
* without blocking.
*
* @throws IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
// 返回剩余可不被阻塞地读取(或跳过)的字节数(估计值)
public int available() throws IOException {
return (pushBack == -1) ? super.available() / 2 : super.available() / 2 + 1;
}
/**
* Skips over and discards {@code n} bytes of data from this
* input stream. The {@code skip} method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly {@code 0}. The actual number of bytes skipped is
* returned. If {@code n} is negative, no bytes are skipped.
* <p>
* The {@code skip} method of {@code LineNumberInputStream} creates
* a byte array and then repeatedly reads into it until
* {@code n} bytes have been read or the end of the stream has
* been reached.
*
* @param n the number of bytes to be skipped.
*
* @return the actual number of bytes skipped.
*
* @throws IOException if an I/O error occurs.
* @see java.io.FilterInputStream#in
*/
// 读取中跳过n个字节,返回实际跳过的字节数
public long skip(long n) throws IOException {
int chunk = 2048;
long remaining = n;
byte[] data;
int nr;
if(n<=0) {
return 0;
}
data = new byte[chunk];
while(remaining>0) {
nr = read(data, 0, (int) Math.min(chunk, remaining));
if(nr<0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
/**
* Returns the current line number.
*
* @return the current line number.
*
* @see #setLineNumber
*/
// 返回当前行号
public int getLineNumber() {
return lineNumber;
}
/**
* Sets the line number to the specified argument.
*
* @param lineNumber the new line number.
*
* @see #getLineNumber
*/
// 修改当前行号(不会修改读游标的位置)
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
/*▲ 杂项 ████████████████████████████████████████████████████████████████████████████████┛ */
}