码迷,mamicode.com
首页 > 编程语言 > 详细

Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream

时间:2016-08-18 12:49:52      阅读:288      评论:0      收藏:0      [点我收藏+]

标签:

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),数据一次性写到底层的输出流

 

Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream

标签:

原文地址:http://www.cnblogs.com/ixenos/p/5729841.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!