Chinaunix首页 | 论坛 | 博客
  • 博客访问: 752866
  • 博文数量: 130
  • 博客积分: 2951
  • 博客等级: 少校
  • 技术积分: 1875
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 18:32
文章分类

全部博文(130)

文章存档

2013年(1)

2012年(129)

分类: Java

2012-03-09 13:10:03

通过源码进行学习

  1. public class BufferedInputStream extends FilterInputStream {

  2.     private static int defaultBufferSize = 8192;

  3.     /*内部的缓冲区*/
  4.     protected volatile byte buf[];

  5.     /**
  6.      * Atomic updater to provide compareAndSet for buf. This is necessary
  7.      * because closes can be asynchronous. We use nullness of buf[] as primary
  8.      * indicator that this stream is closed. (The "in" field is also nulled out
  9.      * on close.)
  10.      */
  11.     private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater
  12.             .newUpdater(BufferedInputStream.class, byte[].class, "buf");

  13.        /*缓冲区内部的有效字节数,在0到buf.length之间*/
  14.     protected int count;

  15.     /**
  16.      * The current position in the buffer. This is the index of the next
  17.      * character to be read from the buf array.
  18.      *


  19.      * This value is always in the range 0 through
  20.      * count. If it is less than count, then
  21.      * buf[pos] is the next byte to be supplied as input; if it is
  22.      * equal to count, then the next read or
  23.      * skip operation will require more bytes to be read from the
  24.      * contained input stream.
  25.      *
  26.      * @see java.io.BufferedInputStream#buf
  27.      */
  28.     /*1. 缓冲区内部的当前位置,也就是下一次从缓冲区读取时的开始位置, 一般处于0到count之间
  29.      2. 如果pos大于count,那么下次读取将从潜在的input stream读取*/
  30.     protected int pos;

  31.     /*1. 当调用mark方法时,记录pos的值,处于-1到pos之间。
  32.      2. 如果没有marked,那么它的值为-1,
  33.      3. 如果做了marked,那么当调用reset之后,buf[markpos]成为第一个将被读取的字节
  34.      4. 如果marpos不是-1, 那么在buf[markpos]到buf[pos-1]之间的字节将被保留在缓冲区中,直到pos和markpos之间的差大于marklimit才会被丢弃
  35.     protected int markpos = -1;

  36.     /**
  37.      * The maximum read ahead allowed after a call to the mark
  38.      * method before subsequent calls to the reset method fail.
  39.      * Whenever the difference between pos and markpos
  40.      * exceeds marklimit, then the mark may be dropped by setting
  41.      * markpos to -1.
  42.      *
  43.      * @see java.io.BufferedInputStream#mark(int)
  44.      * @see java.io.BufferedInputStream#reset()
  45.      */
  46.     /*这个参数一致不太懂,保留英文注释*/
  47.     protected int marklimit;

  48.     private InputStream getInIfOpen() throws IOException {
  49.         InputStream input = in;
  50.         if (input == null)
  51.             throw new IOException("Stream closed");
  52.         return input;
  53.     }

  54.     private byte[] getBufIfOpen() throws IOException {
  55.         byte[] buffer = buf;
  56.         if (buffer == null)
  57.             throw new IOException("Stream closed");
  58.         return buffer;
  59.     }

  60.     public BufferedInputStream(InputStream in) {
  61.         this(in, defaultBufferSize);
  62.     }

  63.     public BufferedInputStream(InputStream in, int size) {
  64.         super(in);
  65.         if (size <= 0) {
  66.             throw new IllegalArgumentException("Buffer size <= 0");
  67.         }
  68.         buf = new byte[size];
  69.     }

  70.     private void fill() throws IOException {
  71.         byte[] buffer = getBufIfOpen();
  72.         if (markpos < 0) /*没有做标记, 这个可以看做是第一次读取时的情况 记做case1*/
  73.             pos = 0;
  74.         else if (pos >= buffer.length) /*说明已经读完了buffer中的最后一个字节*/
  75.             if (markpos > 0) { /*说明做过标记,记做case2*/
  76.                 int sz = pos - markpos; /*计算有多少字节需要保留)
  77.                 System.arraycopy(buffer, markpos, buffer, 0, sz); /*把做了标记之后的字节拷贝到缓冲区的开头*/
  78.                 pos = sz; /*把pos置为保留的那些字节之后的那个位置,也就是下一次要读取的位置*/
  79.                 markpos = 0;
  80.             } else if (buffer.length >= marklimit) { /*我能想到进入到这个分支的情况是,在初始化之后,pos=0,这时调用mark(0),
  81.                                     /*然后一直读到buffer的最后一个字节,
  82.                                     /*然后再读的时候, 这时候pos>=buf.length, markpos=0, buf.length >= marklimit
  83.                 markpos = -1;
  84.                 pos = 0;
  85.             } else { /* grow buffer */ /*我能想到进入到这个分支的情况是,初始化之后,pos=0, 调用mark(>buf.length)
  86.                                     /*然后一直读到buffer的最后一个字节,
  87.                                     /*然后再读的时候, 这时候pos>=buf.length, markpos=0, buf.length < marklimit
  88.                                     /*这时需要扩展空间,new一个新buf,然后把旧buf里的字节拷贝过去,pos定位到
  89.                                     /*拷贝后的那个位置
  90.                 int nsz = pos * 2;
  91.                 if (nsz > marklimit)
  92.                     nsz = marklimit;
  93.                 byte nbuf[] = new byte[nsz];
  94.                 System.arraycopy(buffer, 0, nbuf, 0, pos);
  95.                 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
  96.                     // Can't replace buf if there was an async close.
  97.                     // Note: This would need to be changed if fill()
  98.                     // is ever made accessible to multiple threads.
  99.                     // But for now, the only way CAS can fail is via close.
  100.                     // assert buf == null;
  101.                     throw new IOException("Stream closed");
  102.                 }
  103.                 buffer = nbuf;
  104.             }
  105.         count = pos;
  106.         int n = getInIfOpen().read(buffer, pos, buffer.length - pos); /*从潜在的input stream中读取数据,读取的字节数是n*/
  107.         if (n > 0)
  108.             count = n + pos;
  109.     }

  110.     public synchronized int read() throws IOException {
  111.         if (pos >= count) { /*如果pos>=count,说明pos已经到了有效字节的末尾,需要重新从潜在的inputStream中读取新数据*/
  112.             fill(); /*所以要调用fill()*/
  113.             if (pos >= count)
  114.                 return -1;
  115.         }
  116.         return getBufIfOpen()[pos++] & 0xff;
  117.     }

  118.     private int read1(byte[] b, int off, int len) throws IOException {
  119.         int avail = count - pos;
  120.         if (avail <= 0) {
  121.             /*
  122.              * If the requested length is at least as large as the buffer, and
  123.              * if there is no mark/reset activity, do not bother to copy the
  124.              * bytes into the local buffer. In this way buffered streams will
  125.              * cascade harmlessly.
  126.              */
  127.             if (len >= getBufIfOpen().length && markpos < 0) {
  128.                 return getInIfOpen().read(b, off, len);
  129.             }
  130.             fill();
  131.             avail = count - pos;
  132.             if (avail <= 0)
  133.                 return -1;
  134.         }
  135.         int cnt = (avail < len) ? avail : len;
  136.         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
  137.         pos += cnt;
  138.         return cnt;
  139.     }

  140.     public synchronized int read(byte b[], int off, int len) throws IOException {
  141.         getBufIfOpen(); // Check for closed stream
  142.         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
  143.             throw new IndexOutOfBound***ception();
  144.         } else if (len == 0) {
  145.             return 0;
  146.         }

  147.         int n = 0;
  148.         for (;;) {
  149.             int nread = read1(b, off + n, len - n);
  150.             if (nread <= 0)
  151.                 return (n == 0) ? nread : n;
  152.             n += nread;
  153.             if (n >= len)
  154.                 return n;
  155.             // if not closed but no bytes available, return
  156.             InputStream input = in;
  157.             if (input != null && input.available() <= 0)
  158.                 return n;
  159.         }
  160.     }

  161.     public synchronized long skip(long n) throws IOException {
  162.         getBufIfOpen(); // Check for closed stream
  163.         if (n <= 0) {
  164.             return 0;
  165.         }
  166.         long avail = count - pos; /*先计算剩余的有效字节数*/

  167.         if (avail <= 0) { /*如果没有有效字节了*/
  168.             // If no mark position set then don't keep in buffer
  169.             if (markpos < 0)
  170.                 return getInIfOpen().skip(n); /*直接在潜在的inputStream中skip

  171.             // Fill in buffer to save bytes for reset
  172.             fill(); /*如果做了标记,那么就调用fill(),把标记之后的字节保存,再读取,再准备下面的skip, 记做case3
  173.             avail = count - pos; /*读取后,有效字节数和当前位置的差*/
  174.             if (avail <= 0)
  175.                 return 0;
  176.         }

  177.         long skipped = (avail < n) ? avail : n; /*看看要skip的字节数和可以被skip的字节数哪个小,就用哪个*/
  178.         pos += skipped; /*定位pos到当前位置加上要skip的字节数*/
  179.         return skipped; /*返回实际skip的字节数*/
  180.     }

  181.     public synchronized int available() throws IOException {
  182.         return getInIfOpen().available() + (count - pos);
  183.     }

  184.     public synchronized void mark(int readlimit) {
  185.         marklimit = readlimit;
  186.         markpos = pos;
  187.     }

  188.     public synchronized void reset() throws IOException {
  189.         getBufIfOpen(); // Cause exception if closed
  190.         if (markpos < 0)
  191.             throw new IOException("Resetting to invalid mark");
  192.         pos = markpos;
  193.     }

  194.     public boolean markSupported() {
  195.         return true;
  196.     }

  197.     public void close() throws IOException {
  198.         byte[] buffer;
  199.         while ((buffer = buf) != null) {
  200.             if (bufUpdater.compareAndSet(this, buffer, null)) {
  201.                 InputStream input = in;
  202.                 in = null;
  203.                 if (input != null)
  204.                     input.close();
  205.                 return;
  206.             }
  207.             // Else retry in case a new buf was CASed in fill()
  208.         }
  209.     }
  210. }
准备一个测试文件1.txt, 内容是
012345678901234567890123456789
测试
case 1:
  1. public class BufferInputOutputStreamTest extends BufferedInputStream {
  2.     public BufferInputOutputStreamTest(InputStream in) {
  3.         super(in);
  4.     }
  5.     
  6.     public BufferInputOutputStreamTest(InputStream in , int size){
  7.         super(in, size);
  8.     }
  9.     
  10.     public String toString(){
  11.         return this.buf.toString();
  12.     }

  13.     public static void main(String [] args) throws IOException{
  14.         
  15.         BufferInputOutputStreamTest bis =
  16.                 new BufferInputOutputStreamTest(new FileInputStream("c:\\1.txt"),10);
  17.         
  18.         System.out.println(bis.pos); //输出0
  19.         System.out.println(bis.count); //输出0
  20.         System.out.println(bis.markpos); //输出-1
  21.         
  22.         System.out.println(bis.read());
  23.         
  24.         
  25.         for(int i= 0; i < bis.count; i++){
  26.             System.out.println("buf[" + i + "] is : " + bis.buf[i]);
  27.         }
  28.         /*
  29.          * 上面输出
  30.          *  buf[0] is : 48
  31.             buf[1] is : 49
  32.             buf[2] is : 50
  33.             buf[3] is : 51
  34.             buf[4] is : 52
  35.             buf[5] is : 53
  36.             buf[6] is : 54
  37.             buf[7] is : 55
  38.             buf[8] is : 56
  39.             buf[9] is : 57
  40.          */
  41.         
  42.         System.out.println(bis.pos); //输出1
  43.         System.out.println(bis.count); //输出10
  44.         System.out.println(bis.markpos); //输出-1
  45.     }
  46. }
Case2:

  1. public class BufferInputOutputStreamTest extends BufferedInputStream {
  2.     public BufferInputOutputStreamTest(InputStream in) {
  3.         super(in);
  4.     }
  5.     
  6.     public BufferInputOutputStreamTest(InputStream in , int size){
  7.         super(in, size);
  8.     }
  9.     
  10.     public String toString(){
  11.         return this.buf.toString();
  12.     }

  13.     public static void main(String [] args) throws IOException{
  14.         
  15.         BufferInputOutputStreamTest bis =
  16.                 new BufferInputOutputStreamTest(new FileInputStream("c:\\1.txt"),10);
  17.         
  18.         for(int i = 0; i < 5; i++){
  19.             bis.read();
  20.         }        
  21.         
  22.         for(int i= 0; i < bis.count; i++){
  23.             System.out.println("buf[" + i + "] is : " + bis.buf[i]);
  24.         }
  25.         /*输出
  26.         buf[0] is : 48
  27.         buf[1] is : 49
  28.         buf[2] is : 50
  29.         buf[3] is : 51
  30.         buf[4] is : 52
  31.         buf[5] is : 53
  32.         buf[6] is : 54
  33.         buf[7] is : 55
  34.         buf[8] is : 56
  35.         buf[9] is : 57
  36.         */
  37.         
  38.         bis.mark(5);
  39.         
  40.         System.out.println(bis.pos); //output: 5
  41.         System.out.println(bis.count); //output: 10
  42.         System.out.println(bis.markpos); //output: 5
  43.         System.out.println(bis.marklimit); //output : 5
  44.         
  45.         for(int i = 0; i < 5; i++){
  46.             bis.read();
  47.         }    
  48.         
  49.         System.out.println(bis.pos);//output: 10
  50.         System.out.println(bis.count);//output: 10
  51.         System.out.println(bis.markpos);//output: 5
  52.         System.out.println(bis.marklimit);//output : 5
  53.         System.out.println(bis.pos >= bis.buf.length);//output :true
  54.         
  55.         
  56.         bis.read(); //這個read會導致把markpos之後的5個字節拷貝到緩衝區開頭,
  57.                     //然後讀取新的5個字節到緩衝區
  58.         
  59.         for(int i= 0; i < bis.count; i++){
  60.             System.out.println("buf[" + i + "] is : " + bis.buf[i]);
  61.         }
  62.         /*
  63.              輸出, 前5個是原來的后5個,現在拷貝到了開頭,后5個是新讀入的5個
  64.          buf[0] is : 53
  65.         buf[1] is : 54
  66.         buf[2] is : 55
  67.         buf[3] is : 56
  68.         buf[4] is : 57
  69.         buf[5] is : 48
  70.         buf[6] is : 49
  71.         buf[7] is : 50
  72.         buf[8] is : 51
  73.         buf[9] is : 52
  74.          */
  75.     }
  76. }
Case3

  1. public class BufferInputOutputStreamTest extends BufferedInputStream {
  2.     public BufferInputOutputStreamTest(InputStream in) {
  3.         super(in);
  4.     }
  5.     
  6.     public BufferInputOutputStreamTest(InputStream in , int size){
  7.         super(in, size);
  8.     }
  9.     
  10.     public String toString(){
  11.         return this.buf.toString();
  12.     }

  13.     public static void main(String [] args) throws IOException{
  14.         
  15.         BufferInputOutputStreamTest bis =
  16.                 new BufferInputOutputStreamTest(new FileInputStream("c:\\1.txt"),10);
  17.         
  18.         for(int i = 0; i < 4; i++){
  19.             bis.read(); //讀取4次,這時pos=4,count=10
  20.         }    
  21.         
  22.         bis.mark(4);
  23.         
  24.         for(int i = 0; i < 6; i++){
  25.             bis.read(); //讀取6次,這時pos=10,count=10
  26.         }    
  27.         
  28.         for(int i = 0; i < bis.buf.length; i++){
  29.             System.out.println("bis[" + i + "] is : " + bis.buf[i]);
  30.         }
  31.         
  32.         System.out.println(bis.pos); //output: 10
  33.         System.out.println(bis.count); //output: 10
  34.         System.out.println(bis.markpos); //output: 4
  35.         System.out.println(bis.marklimit); //output : 4
  36.         
  37.         System.out.println(bis.skip(12)); //調用fill(),由於此時markpos=4, 所以會把後面的10-4=6個字節先拷貝到buf的開頭,然後再
  38.                         //讀入4個字節,在fill()置pos=6, 然後在skip()里計算avail=count-pos=4,
  39.                         //4小於傳入的12, 所以返回4, 並且pos=4+pos,最終pos=10,指向下一次堯讀取的位置
  40.         
  41.         for(int i = 0; i < bis.buf.length; i++){
  42.             System.out.println("bis[" + i + "] is : " + bis.buf[i]);
  43.         }
  44.         //後面4個是新讀入的了。
  45.         
  46.         System.out.println(bis.pos); //output: 10
  47.         System.out.println(bis.count); //output: 10
  48.         System.out.println(bis.markpos); //output: 4
  49.         System.out.println(bis.marklimit); //output : 4
  50.     }
  51. }









阅读(3299) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~