forked from kangjianwei/LearningJDK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathByteArrayOutputStream.java
390 lines (350 loc) · 15.1 KB
/
ByteArrayOutputStream.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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/*
* Copyright (c) 1994, 2018, 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;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Objects;
/**
* This class implements an output stream in which the data is
* written into a byte array. The buffer automatically grows as data
* is written to it.
* The data can be retrieved using {@code toByteArray()} and
* {@code toString()}.
* <p>
* Closing a {@code ByteArrayOutputStream} has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an {@code IOException}.
*
* @author Arthur van Hoff
* @since 1.0
*/
/*
* 字节数组输出流
*
* 写入的内容会先存入内部字节缓存区,这一点与BufferedOutputStream是相似的。
* 不同点在于,BufferedOutputStream中包装了输出流,当缓冲区满时,会将其中的数据自动刷新到输出流。
* 而ByteArrayOutputStream中没有包装输出流,所有写入的数据都会存入内部缓存区,直到被动地调用writeTo后,
* 才会将内部缓存区的数据转移到指定的输出流。
*/
public class ByteArrayOutputStream extends OutputStream {
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* The buffer where data is stored.
*/
protected byte[] buf; // 内部缓冲区
/**
* The number of valid bytes in the buffer.
*/
protected int count; // 记录写入缓冲区的字节数
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Creates a new {@code ByteArrayOutputStream}. The buffer capacity is
* initially 32 bytes, though its size increases if necessary.
*/
public ByteArrayOutputStream() {
this(32);
}
/**
* Creates a new {@code ByteArrayOutputStream}, with a buffer capacity of
* the specified size, in bytes.
*
* @param size the initial size.
*
* @throws IllegalArgumentException if size is negative.
*/
public ByteArrayOutputStream(int size) {
if(size<0) {
throw new IllegalArgumentException("Negative initial size: " + size);
}
buf = new byte[size];
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 写 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Writes the specified byte to this {@code ByteArrayOutputStream}.
*
* @param b the byte to be written.
*/
// 将指定的字节写入到内部缓存区
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
/**
* Writes the complete contents of the specified byte array
* to this {@code ByteArrayOutputStream}.
*
* @param b the data.
*
* @throws NullPointerException if {@code b} is {@code null}.
* @apiNote This method is equivalent to {@link #write(byte[], int, int)
* write(b, 0, b.length)}.
* @since 11
*/
// 将字节数组b的内容写入到内部缓存区
public void writeBytes(byte[] b) {
write(b, 0, b.length);
}
/**
* Writes {@code len} bytes from the specified byte array
* starting at offset {@code off} to this {@code ByteArrayOutputStream}.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*
* @throws NullPointerException if {@code b} is {@code null}.
* @throws IndexOutOfBoundsException if {@code off} is negative,
* {@code len} is negative, or {@code len} is greater than
* {@code b.length - off}
*/
// 将字节数组b中off处起的len个字节写入到输出流
public synchronized void write(byte[] b, int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
ensureCapacity(count + len);
System.arraycopy(b, off, buf, count, len);
count += len;
}
/**
* Writes the complete contents of this {@code ByteArrayOutputStream} to
* the specified output stream argument, as if by calling the output
* stream's write method using {@code out.write(buf, 0, count)}.
*
* @param out the output stream to which to write the data.
*
* @throws NullPointerException if {@code out} is {@code null}.
* @throws IOException if an I/O error occurs.
*/
// 将内部缓冲区的数据写入到指定的输出流中(不会清空内部缓存区)
public synchronized void writeTo(OutputStream out) throws IOException {
// 从字节数组buf中选取count个字节,然后将其写入到输出流
out.write(buf, 0, count);
}
/*▲ 写 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 杂项 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Closing a {@code ByteArrayOutputStream} has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an {@code IOException}.
*/
// 关闭输出流(此处无效)
public void close() throws IOException {
}
/**
* Resets the {@code count} field of this {@code ByteArrayOutputStream}
* to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
// 清空内部字节缓存区
public synchronized void reset() {
count = 0;
}
/**
* Returns the current size of the buffer.
*
* @return the value of the {@code count} field, which is the number
* of valid bytes in this output stream.
*
* @see java.io.ByteArrayOutputStream#count
*/
// 返回内部字节缓存区中的字节数量
public synchronized int size() {
return count;
}
/*▲ 杂项 ████████████████████████████████████████████████████████████████████████████████┛ */
/**
* Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this output stream, as a byte array.
*
* @see java.io.ByteArrayOutputStream#size()
*/
// 返回内部字节缓冲区中的数据
public synchronized byte[] toByteArray() {
return Arrays.copyOf(buf, count);
}
/**
* Converts the buffer's contents into a string decoding bytes using the
* platform's default character set. The length of the new {@code String}
* is a function of the character set, and hence may not be equal to the
* size of the buffer.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with the default replacement string for the platform's
* default character set. The {@linkplain java.nio.charset.CharsetDecoder}
* class should be used when more control over the decoding process is
* required.
*
* @return String decoded from the buffer's contents.
*
* @since 1.1
*/
// 以JVM默认字符集格式解析内部字节缓冲区中的数据,进而构造String
public synchronized String toString() {
return new String(buf, 0, count);
}
/**
* Converts the buffer's contents into a string by decoding the bytes using
* the named {@link java.nio.charset.Charset charset}.
*
* <p> This method is equivalent to {@code #toString(charset)} that takes a
* {@link java.nio.charset.Charset charset}.
*
* <p> An invocation of this method of the form
*
* <pre> {@code
* ByteArrayOutputStream b = ...
* b.toString("UTF-8")
* }
* </pre>
*
* behaves in exactly the same way as the expression
*
* <pre> {@code
* ByteArrayOutputStream b = ...
* b.toString(StandardCharsets.UTF_8)
* }
* </pre>
*
* @param charsetName the name of a supported
* {@link java.nio.charset.Charset charset}
*
* @return String decoded from the buffer's contents.
*
* @throws UnsupportedEncodingException If the named charset is not supported
* @since 1.1
*/
// 以charsetName格式的字符集解析内部字节缓冲区中的数据,进而构造String
public synchronized String toString(String charsetName) throws UnsupportedEncodingException {
return new String(buf, 0, count, charsetName);
}
/**
* Converts the buffer's contents into a string by decoding the bytes using
* the specified {@link java.nio.charset.Charset charset}. The length of the new
* {@code String} is a function of the charset, and hence may not be equal
* to the length of the byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with the charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param charset the {@linkplain java.nio.charset.Charset charset}
* to be used to decode the {@code bytes}
*
* @return String decoded from the buffer's contents.
*
* @since 10
*/
// 以charset字符集格式解析内部字节缓冲区中的数据,进而构造String
public synchronized String toString(Charset charset) {
return new String(buf, 0, count, charset);
}
/**
* Creates a newly allocated string. Its size is the current size of
* the output stream and the valid contents of the buffer have been
* copied into it. Each character <i>c</i> in the resulting string is
* constructed from the corresponding element <i>b</i> in the byte
* array such that:
* <blockquote><pre>{@code
* c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))
* }</pre></blockquote>
*
* @param hibyte the high byte of each resulting Unicode character.
*
* @return the current contents of the output stream, as a string.
*
* @see java.io.ByteArrayOutputStream#size()
* @see java.io.ByteArrayOutputStream#toString(String)
* @see java.io.ByteArrayOutputStream#toString()
* @deprecated This method does not properly convert bytes into characters.
* As of JDK 1.1, the preferred way to do this is via the
* {@link #toString(String charsetName)} or {@link #toString(Charset charset)}
* method, which takes an encoding-name or charset argument,
* or the {@code toString()} method, which uses the platform's default
* character encoding.
*/
// ▶ 9 ※ 过时
@Deprecated
public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, count);
}
/**
* Increases the capacity if necessary to ensure that it can hold
* at least the number of elements specified by the minimum
* capacity argument.
*
* @param minCapacity the desired minimum capacity
*
* @throws OutOfMemoryError if {@code minCapacity < 0}. This is
* interpreted as a request for the unsatisfiably large capacity
* {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
*/
// 确保内部缓存区容量足够大
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if(minCapacity - buf.length>0) {
grow(minCapacity);
}
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
// 对内部缓存区进行扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = buf.length;
int newCapacity = oldCapacity << 1;
if(newCapacity - minCapacity<0) {
newCapacity = minCapacity;
}
if(newCapacity - MAX_ARRAY_SIZE>0) {
newCapacity = hugeCapacity(minCapacity);
}
buf = Arrays.copyOf(buf, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// overflow
if(minCapacity<0) {
throw new OutOfMemoryError();
}
return (minCapacity>MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
}