Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream
@author ixenos
概念
BufferedInput/OutputStream是实现缓存的过滤流,他们分别是FilterInput/OutputStream的子类。
BufferedInputStream工作流程
stream-->buf--read buf-->I
1.当一个BufferedInputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,BufferedInputStream预先在缓冲区存储来自连接输入流的数据;
1 private static int DEFAULT_BUFFER_SIZE = 8192; 2 protected volatile byte buf[]; 3 4 public BufferedInputStream(InputStream in) { 5 this(in, DEFAULT_BUFFER_SIZE); 6 } 7 8 9 public BufferedInputStream(InputStream in, int size) { 10 super(in); 11 if (size <= 0) { 12 throw new IllegalArgumentException("Buffer size <= 0"); 13 } 14 buf = new byte[size]; 15 }
2.当BufferedInputStream的read方法被调用时,数据将从缓冲区中移出,而不是底层的输入流;
3.当BufferedInputStream缓冲区数据用完时,他自动从底层输入流中补充数据。
BufferedInputStream的read方法源码分析
1 public synchronized int read() throws IOException { 2 if (pos >= count) { 3 fill(); 4 if (pos >= count) 5 return -1; 6 } 7 return getBufIfOpen()[pos++] & 0xff; 8 } 9 10 //getBufIfOpen对buf进行非空判断,然后返回buf值传递给buffer的一个byte[]数组 11 private byte[] getBufIfOpen() throws IOException { 12 byte[] buffer = buf; 13 if (buffer == null) 14 throw new IOException("Stream closed"); 15 return buffer; 16 }
BufferedInputStream的read(byte b[], int off, int len)源码分析
1 //BufferedInputStream中的read进指定内存的方法 2 public synchronized int read(byte b[], int off, int len) 3 throws IOException 4 { 5 //缓冲流关闭时维护的buf消失,返回的buffer等于null,因为buf值传递给buffer,如下 6 /* 7 private byte[] getBufIfOpen() throws IOException { 8 byte[] buffer = buf; 9 if (buffer == null) 10 throw new IOException("Stream closed"); 11 return buffer; 12 } 13 */ 14 getBufIfOpen(); // Check for closed stream 15 //范围判断 16 if ((off | len | (off + len) | (b.length - (off + len))) < 0) { 17 throw new IndexOutOfBoundsException(); 18 } else if (len == 0) { 19 return 0; 20 } 21 22 int n = 0; 23 //循环写数据到b,知道buffer数据不足返回-1,此时nread已累加记录 24 for (;;) { 25 int nread = read1(b, off + n, len - n); 26 if (nread <= 0) 27 return (n == 0) ? nread : n; 28 n += nread; 29 //读完指定长度时返回 30 if (n >= len) 31 return n; 32 // if not closed but no bytes available, return 33 //没读完指定长度,但缓冲区没数据时返回当前n 34 InputStream input = in; 35 if (input != null && input.available() <= 0) 36 return n; 37 } 38 } 39 40 41 /** 42 * read1方法是该read底层用来读取缓冲区buf的数据进指定数组的方法 43 * 而fill方法又是read1方法中用来读取底层字节流到缓冲区buf的方法 44 * 读取数据写进指定数组的一部分,必要时每次从底层流尽量读取数据 45 */ 46 private int read1(byte[] b, int off, int len) throws IOException { 47 int avail = count - pos; 48 if (avail <= 0) { 49 /* 如果所请求的长度至少和缓冲区一样大,并且 50 如果没有标记/复位活动,就没必要用缓冲区了,将直接从底层 流读取数据。以这种方式缓冲流将 51 级联无害 52 */ 53 if (len >= getBufIfOpen().length && markpos < 0) { 54 //getInIfOpen返回的是经非空判断的底层流,所以调用的自然也是底层流的read方法,写进指定的内存b 55 return getInIfOpen().read(b, off, len); 56 } 57 //请求fill()方法来读取底层流数据 58 fill(); 59 avail = count - pos; 60 if (avail <= 0) return -1; 61 } 62 int cnt = (avail < len) ? avail : len; 63 System.arraycopy(getBufIfOpen(), pos, b, off, cnt); 64 pos += cnt; 65 return cnt; 66 } 67 68 69 //fill()方法填充空间,是底层用来读取流数据到缓冲区buf 70 /** 71 * Fills the buffer with more data, taking into account 72 * shuffling and other tricks for dealing with marks. 73 * Assumes that it is being called by a synchronized method. 74 * This method also assumes that all data has already been read in, 75 * hence pos > count. 76 */ 77 private void fill() throws IOException { 78 byte[] buffer = getBufIfOpen(); 79 //markpos是起始读取buffer的位置,pos是终点位置 80 //起始小于零表明没有pos移动,从源码可知 81 if (markpos < 0) 82 pos = 0; /* no mark: throw away the buffer */ 83 //当pos比buffer更长时 84 else if (pos >= buffer.length) /* no room left in buffer */ 85 //起始pos也有前移时 86 if (markpos > 0) { /* can throw away early part of the buffer */ 87 int sz = pos - markpos; 88 System.arraycopy(buffer, markpos, buffer, 0, sz); 89 pos = sz; 90 markpos = 0; 91 //buffer大小超过理论规模时 92 } else if (buffer.length >= marklimit) { 93 markpos = -1; /* buffer got too big, invalidate mark */ 94 pos = 0; /* drop buffer contents */ 95 //buffer大小超过本地VM内存限制时:MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8 96 } else if (buffer.length >= MAX_BUFFER_SIZE) { 97 throw new OutOfMemoryError("Required array size too large"); 98 } else { /* grow buffer */ 99 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? 100 pos * 2 : MAX_BUFFER_SIZE; 101 if (nsz > marklimit) 102 nsz = marklimit; 103 byte nbuf[] = new byte[nsz]; 104 System.arraycopy(buffer, 0, nbuf, 0, pos); 105 /*AtomicReferenceFieldUpdater是一个基于反射的工具类, 106 它能对指定类的指定的volatile引用字段进行原子更新。 107 (注意这个字段不能是private的) , 108 从源码知getBufIfOpen返回的是值传递的protected volatile byte buf[] 109 */ 110 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { 111 // Can‘t replace buf if there was an async close. 112 // Note: This would need to be changed if fill() 113 // is ever made accessible to multiple threads. 114 // But for now, the only way CAS can fail is via close. 115 // assert buf == null; 116 throw new IOException("Stream closed"); 117 } 118 buffer = nbuf; 119 } 120 //pos小于buf.length时,从底层流到缓冲区,使用InputStream的read(byte[])方法 121 count = pos; 122 int n = getInIfOpen().read(buffer, pos, buffer.length - pos); 123 if (n > 0) 124 count = n + pos; 125 } 126
BufferedOutputStream工作流程
I--write buf-->buf-->stream
1.BufferedOutputStream在内部缓冲区存储程序的输出数据,这样就不会每次调用write方法时,就把数据写到底层的输出流;
2.当BufferedOutputStream的内部缓冲区满或者它被刷新(flush),数据一次性写到底层的输出流。
时间: 2024-10-24 03:51:52