0%

Buffered包装的IO流效率

文章字数:406,阅读全文大约需要1分钟

BufferIO流是为了效率而创造出来的,然而实际上不是所有的情况下效率都比普通io高。

源码分析

  1. BufferedInputStream
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
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;
}
}


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;
}

BufferedInputStreamread方法本质上也是调用FilterInputStreamread方法,IO的次数差不多,特殊情况下还会比FilterInputStream多。

  1. BufferedOutputStream
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
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}

public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}

public synchronized void write(byte b[], int off, int len) throws IOException {
if (len >= buf.length) {
/* If the request length exceeds the size of the output buffer,
flush the output buffer and then write the data directly.
In this way buffered streams will cascade harmlessly. */
flushBuffer();
out.write(b, off, len);
return;
}
if (len > buf.length - count) {
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}

初始化的时候声明了一个8192大小的byte[]数组,每次写入都是直接写入数组中。当调用刷新方法,或者数组满了才会调用FilterOutputStreamwrite将数组中的数据写入IO

分析

  1. read方法在获取到的长度小于预期的长度时会再次尝试读取剩余的长度,其它和原生IO一样

  2. write方法本质是先把数据写入内置的byte[]中,等到了一定大小再调用父类方法一次性写入。和自己在外部把信息写入byte[]再写入是一样的。

  3. write方法在写入的数据大于初始化缓冲区的情况下还会增加IO次数,因为写入后检测到大于缓存区就会马上写入IO,再写入剩下的。