服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java IO学习之缓冲输入流(BufferedInputStream)

Java IO学习之缓冲输入流(BufferedInputStream)

2020-08-12 11:27java教程网 Java教程

这篇文章主要介绍了Java IO学习之缓冲输入流(BufferedInputStream)的相关资料,需要的朋友可以参考下

Java IO  BufferedInputStream

概要:

BufferedInputStream是缓冲输入流,继承于FilterInputStream,作用是为另一个输入流添加一些功能,本质上是通过一个内部缓冲数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当通过read()读取数据时,BufferedInputStream会将输入流的数据分批的填入到缓冲区中,每当缓冲区的数据读完之后,输入流会再次填充数据缓冲区,直到读完数据。

BufferedInputStream主要的函数列表:

?
1
2
3
4
5
6
7
8
9
10
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
synchronized int available()
void close()
synchronized void mark(int readlimit)
boolean markSupported()
synchronized int read()
synchronized int read(byte[] buffer, int offset, int byteCount)
synchronized void reset()
synchronized long skip(long byteCount)

示例代码:

?
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
public class BufferedInputStreamTest {
 
  private static final int LEN = 5;
 
  public static void main(String[] args) {
    testBufferedInputStream() ;
  }
  private static void testBufferedInputStream() {
 
    // 创建BufferedInputStream字节流,内容是ArrayLetters数组
    try {
      File file = new File("file.txt");
      InputStream in =new BufferedInputStream(new FileInputStream(file), 512);
 
      // 从字节流中读取5个字节。“abcde”,a对应0x61,b对应0x62,依次类推...
      for (int i=0; i<LEN; i++) {
      // 若能继续读取下一个字节,则读取下一个字节
        if (in.available() >= 0) {
        // 读取“字节流的下一个字节”
        int tmp = in.read();
        System.out.printf("%d : 0x%s\n", i, Integer.toHexString(tmp));
        }
      }
 
      // 若“该字节流”不支持标记功能,则直接退出
      if (!in.markSupported()) {
        System.out.println("make not supported!");
        return ;
      }
 
      // 标记“当前索引位置”,即标记第6个位置的元素--“f”
      // 1024对应marklimit
      in.mark(1024);
 
      // 跳过22个字节。
      in.skip(22);
 
      // 读取5个字节
      byte[] buf = new byte[LEN];
      in.read(buf, 0, LEN);
      // 将buf转换为String字符串。
      String str1 = new String(buf);
      System.out.printf("str1=%s\n", str1);
 
      // 重置“输入流的索引”为mark()所标记的位置,即重置到“f”处。
      in.reset();
      // 从“重置后的字节流”中读取5个字节到buf中。即读取“fghij”
      in.read(buf, 0, LEN);
      // 将buf转换为String字符串。
      String str2 = new String(buf);
      System.out.printf("str2=%s\n", str2);
 
      in.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (SecurityException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

运行结果:

?
1
2
3
4
5
6
7
0 : 0x61
1 : 0x62
2 : 0x63
3 : 0x64
4 : 0x65
str1=12345
str2=fghij

基于JDK8的BufferInputStream代码:

?
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
public class BufferedInputStream extends FilterInputStream {
 
  private static int DEFAULT_BUFFER_SIZE = 8192;//默认缓冲区大小为8X1024
  private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
  protected volatile byte buf[]; //缓冲数组
 
  /**
   * Atomic updater to provide compareAndSet for buf. This is
   * necessary because closes can be asynchronous. We use nullness
   * of buf[] as primary indicator that this stream is closed. (The
   * "in" field is also nulled out on close.)
   */
  private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
      AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class, byte[].class, "buf");
  //值在0到buf.len之间
  protected int count;
  //在buffer的当前位置,下一个字符被读取
  protected int pos;
  //值为mark函数最近被调用的时候,值为-1到pos
  protected int markpos = -1;
 
  /**
   * The maximum read ahead allowed after a call to the
   * <code>mark</code> method before subsequent calls to the
   * <code>reset</code> method fail.
   * Whenever the difference between <code>pos</code>
   * and <code>markpos</code> exceeds <code>marklimit</code>,
   * then the mark may be dropped by setting
   * <code>markpos</code> to <code>-1</code>.
   *
   * @see   java.io.BufferedInputStream#mark(int)
   * @see   java.io.BufferedInputStream#reset()
   */
 
  protected int marklimit;
 
  /**
   * Check to make sure that underlying input stream has not been
   * nulled out due to close; if not return it;
   */
  //
  private InputStream getInIfOpen() throws IOException {
    InputStream input = in;
    if (input == null)
      throw new IOException("Stream closed");
    return input;
  }
 
  /**
   * Check to make sure that buffer has not been nulled out due to
   * close; if not return it;
   */
  private byte[] getBufIfOpen() throws IOException {
    byte[] buffer = buf;
    if (buffer == null)
      throw new IOException("Stream closed");
    return buffer;
  }
 
  /**
   * Creates a <code>BufferedInputStream</code>
   * and saves its argument, the input stream
   * <code>in</code>, for later use. An internal
   * buffer array is created and stored in <code>buf</code>.
   *
   * @param  in  the underlying input stream.
   */
  //带InputStream的构造函数
  public BufferedInputStream(InputStream in) {
      this(in, DEFAULT_BUFFER_SIZE);
  }
 
  /**
   * Creates a <code>BufferedInputStream</code>
   * with the specified buffer size,
   * and saves its argument, the input stream
   * <code>in</code>, for later use. An internal
   * buffer array of length <code>size</code>
   * is created and stored in <code>buf</code>.
   *
   * @param  in   the underlying input stream.
   * @param  size  the buffer size.
   * @exception IllegalArgumentException if {@code size <= 0}.
   */
  //带InputStream和大小的构造函数
  public BufferedInputStream(InputStream in, int size) {
    super(in);
    if (size <= 0) {
        throw new IllegalArgumentException("Buffer size <= 0");
    }
    buf = new byte[size];
  }
 
  /**
   * Fills the buffer with more data, taking into account
   * shuffling and other tricks for dealing with marks.
   * Assumes that it is being called by a synchronized method.
   * This method also assumes that all data has already been read in,
   * hence pos > count.
   */
  //
  private void fill() throws IOException {
    byte[] buffer = getBufIfOpen();
    if (markpos < 0)
      pos = 0;      /* no mark: throw away the buffer */
    else if (pos >= buffer.length) /* no room left in buffer */
      if (markpos > 0) { /* can throw away early part of the buffer */
        int sz = pos - markpos;
        System.arraycopy(buffer, markpos, buffer, 0, sz);
        pos = sz;
        markpos = 0;
      } else if (buffer.length >= marklimit) {
         markpos = -1;  /* buffer got too big, invalidate mark */
         pos = 0;    /* drop buffer contents */
      } else if (buffer.length >= MAX_BUFFER_SIZE) {
        throw new OutOfMemoryError("Required array size too large");
      } else {      /* grow buffer */
        int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
        pos * 2 : MAX_BUFFER_SIZE;
        if (nsz > marklimit)
          nsz = marklimit;
        byte nbuf[] = new byte[nsz];
        System.arraycopy(buffer, 0, nbuf, 0, pos);
        if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
          // Can't replace buf if there was an async close.
          // Note: This would need to be changed if fill()
          // is ever made accessible to multiple threads.
          // But for now, the only way CAS can fail is via close.
          // assert buf == null;
          throw new IOException("Stream closed");
        }
        buffer = nbuf;
      }
    count = pos;
    int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
    if (n > 0)
      count = n + pos;
    }
 
  /**
   * See
   * the general contract of the <code>read</code>
   * method of <code>InputStream</code>.
   *
   * @return   the next byte of data, or <code>-1</code> if the end of the
   *       stream is reached.
   * @exception IOException if this input stream has been closed by
   *             invoking its {@link #close()} method,
   *             or an I/O error occurs.
   * @see    java.io.FilterInputStream#in
   */
  //读下一个字节,没有数据返回-1
  public synchronized int read() throws IOException {
    if (pos >= count) {
      fill();
      if (pos >= count)
        return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;
  }
 
  /**
   * Read characters into a portion of an array, reading from the underlying
   * stream at most once if necessary.
   */
  private int read1(byte[] b, int off, int len) throws IOException {
    int avail = count - pos;
    if (avail <= 0) {
      /* If the requested length is at least as large as the buffer, and
        if there is no mark/reset activity, do not bother to copy the
        bytes into the local buffer. In this way buffered streams will
        cascade harmlessly. */
      if (len >= getBufIfOpen().length && markpos < 0) {
        return getInIfOpen().read(b, off, len);
      }
      fill();
      avail = count - pos;
      if (avail <= 0) return -1;
    }
    int cnt = (avail < len) ? avail : len;
    System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
    pos += cnt;
    return cnt;
  }
 
  /**
   * Reads bytes from this byte-input stream into the specified byte array,
   * starting at the given offset.
   *
   * <p> This method implements the general contract of the corresponding
   * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
   * the <code>{@link InputStream}</code> class. As an additional
   * convenience, it attempts to read as many bytes as possible by repeatedly
   * invoking the <code>read</code> method of the underlying stream. This
   * iterated <code>read</code> continues until one of the following
   * conditions becomes true: <ul>
   *
   *  <li> The specified number of bytes have been read,
   *
   *  <li> The <code>read</code> method of the underlying stream returns
   *  <code>-1</code>, indicating end-of-file, or
   *
   *  <li> The <code>available</code> method of the underlying stream
   *  returns zero, indicating that further input requests would block.
   *
   * </ul> If the first <code>read</code> on the underlying stream returns
   * <code>-1</code> to indicate end-of-file then this method returns
   * <code>-1</code>. Otherwise this method returns the number of bytes
   * actually read.
   *
   * <p> Subclasses of this class are encouraged, but not required, to
   * attempt to read as many bytes as possible in the same fashion.
   *
   * @param   b   destination buffer.
   * @param   off  offset at which to start storing bytes.
   * @param   len  maximum number of bytes to read.
   * @return   the number of bytes read, or <code>-1</code> if the end of
   *       the stream has been reached.
   * @exception IOException if this input stream has been closed by
   *             invoking its {@link #close()} method,
   *             or an I/O error occurs.
   */
  //
  public synchronized int read(byte b[], int off, int len)throws IOException
  {
    getBufIfOpen(); // Check for closed stream
    if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
      throw new IndexOutOfBoundsException();
    } else if (len == 0) {
      return 0;
    }
 
    int n = 0;
    for (;;) {
      int nread = read1(b, off + n, len - n);
      if (nread <= 0)
        return (n == 0) ? nread : n;
      n += nread;
      if (n >= len)
        return n;
      // if not closed but no bytes available, return
      InputStream input = in;
      if (input != null && input.available() <= 0)
        return n;
    }
  }
 
  /**
   * See the general contract of the <code>skip</code>
   * method of <code>InputStream</code>.
   *
   * @exception IOException if the stream does not support seek,
   *             or if this input stream has been closed by
   *             invoking its {@link #close()} method, or an
   *             I/O error occurs.
   */
  //跳过n长的数据
  public synchronized long skip(long n) throws IOException {
    getBufIfOpen(); // Check for closed stream
    if (n <= 0) {
      return 0;
    }
    long avail = count - pos;
 
    if (avail <= 0) {
      // If no mark position set then don't keep in buffer
      if (markpos <0)
        return getInIfOpen().skip(n);
 
      // Fill in buffer to save bytes for reset
      fill();
      avail = count - pos;
      if (avail <= 0)
        return 0;
    }
 
    long skipped = (avail < n) ? avail : n;
    pos += skipped;
    return skipped;
  }
 
  /**
   * Returns an estimate of the number of bytes that can be read (or
   * skipped over) from this input stream without blocking by the next
   * invocation of a method for this input stream. The next invocation might be
   * the same thread or another thread. A single read or skip of this
   * many bytes will not block, but may read or skip fewer bytes.
   * <p>
   * This method returns the sum of the number of bytes remaining to be read in
   * the buffer (<code>count - pos</code>) and the result of calling the
   * {@link java.io.FilterInputStream#in in}.available().
   *
   * @return   an estimate of the number of bytes that can be read (or skipped
   *       over) from this input stream without blocking.
   * @exception IOException if this input stream has been closed by
   *             invoking its {@link #close()} method,
   *             or an I/O error occurs.
   */
  //返回还有多少数据可以读
  public synchronized int available() throws IOException {
    int n = count - pos;
    int avail = getInIfOpen().available();
    return n > (Integer.MAX_VALUE - avail)? Integer.MAX_VALUE: n + avail;
  }
 
  /**
   * See the general contract of the <code>mark</code>
   * method of <code>InputStream</code>.
   *
   * @param  readlimit  the maximum limit of bytes that can be read before
   *           the mark position becomes invalid.
   * @see   java.io.BufferedInputStream#reset()
   */
  public synchronized void mark(int readlimit) {
    marklimit = readlimit;
    markpos = pos;
  }
 
  /**
   * See the general contract of the <code>reset</code>
   * method of <code>InputStream</code>.
   * <p>
   * If <code>markpos</code> is <code>-1</code>
   * (no mark has been set or the mark has been
   * invalidated), an <code>IOException</code>
   * is thrown. Otherwise, <code>pos</code> is
   * set equal to <code>markpos</code>.
   *
   * @exception IOException if this stream has not been marked or,
   *         if the mark has been invalidated, or the stream
   *         has been closed by invoking its {@link #close()}
   *         method, or an I/O error occurs.
   * @see    java.io.BufferedInputStream#mark(int)
   */
  public synchronized void reset() throws IOException {
    getBufIfOpen(); // Cause exception if closed
    if (markpos < 0)
      throw new IOException("Resetting to invalid mark");
    pos = markpos;
  }
 
  /**
   * Tests if this input stream supports the <code>mark</code>
   * and <code>reset</code> methods. The <code>markSupported</code>
   * method of <code>BufferedInputStream</code> returns
   * <code>true</code>.
   *
   * @return a <code>boolean</code> indicating if this stream type supports
   *     the <code>mark</code> and <code>reset</code> methods.
   * @see   java.io.InputStream#mark(int)
   * @see   java.io.InputStream#reset()
   */
  //是否支持标记
  public boolean markSupported() {
    return true;
  }
 
  /**
   * Closes this input stream and releases any system resources
   * associated with the stream.
   * Once the stream has been closed, further read(), available(), reset(),
   * or skip() invocations will throw an IOException.
   * Closing a previously closed stream has no effect.
   *
   * @exception IOException if an I/O error occurs.
   */
  //关闭资源 
  public void close() throws IOException {
    byte[] buffer;
    while ( (buffer = buf) != null) {
      if (bufUpdater.compareAndSet(this, buffer, null)) {
        InputStream input = in;
        in = null;
        if (input != null)
          input.close();
        return;
      }
      // Else retry in case a new buf was CASed in fill()
    }
  }
}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

延伸 · 阅读

精彩推荐