注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

anqiang专栏

不要问细节是怎么搞的,源码说明一切

 
 
 

日志

 
 

BufferedIndexInput源码分析  

2009-11-30 10:23:43|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 

BufferedIndexInput负责从文件中读入信息。

代码展示:

package org.apache.lucene.store;

/**

 * Licensed to the Apache Software Foundation (ASF) under one or more

 * contributor license agreements.  See the NOTICE file distributed with

 * this work for additional information regarding copyright ownership.

 * The ASF licenses this file to You under the Apache License, Version 2.0

 * (the "License"); you may not use this file except in compliance with

 * the License.  You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import java.io.IOException;

/** Base implementation class for buffered {@link IndexInput}. */

public abstract class BufferedIndexInput extends IndexInput {

  /** Default buffer size */

/**

 * 很奇怪的是BufferedIndexOutput的BUFFER_SIZE大小与这个不同

 * 1KB

 * 

 */

//大小在1KB

  public static final int BUFFER_SIZE = 1024;

  private int bufferSize = BUFFER_SIZE;

  protected byte[] buffer;

  /**

   * 文件指针位置

   */

  private long bufferStart = 0;   // position in file of buffer

  private int bufferLength = 0;   // end of valid bytes

  private int bufferPosition = 0;   // next byte to read

  public byte readByte() throws IOException {

    if (bufferPosition >= bufferLength)

      refill();

    return buffer[bufferPosition++];

  }

  public BufferedIndexInput() {}

  /** Inits BufferedIndexInput with a specific bufferSize */

  public BufferedIndexInput(int bufferSize) {

    checkBufferSize(bufferSize);

    this.bufferSize = bufferSize;

  }

  /** Change the buffer size used by this IndexInput */

  public void setBufferSize(int newSize) {

    assert buffer == null || bufferSize == buffer.length"buffer=" + buffer + " bufferSize=" + bufferSize + " buffer.length=" + (buffer != null ? buffer.length : 0);

    if (newSize != bufferSize) {

      checkBufferSize(newSize);

      bufferSize = newSize;

      if (buffer != null) {

        // Resize the existing buffer and carefully save as

        // many bytes as possible starting from the current

        // bufferPosition

        byte[] newBuffer = new byte[newSize];

        final int leftInBuffer = bufferLength-bufferPosition;

        final int numToCopy;

        if (leftInBuffer > newSize)

          numToCopy = newSize;

        else

          numToCopy = leftInBuffer;

        System.arraycopy(bufferbufferPosition, newBuffer, 0, numToCopy);

        bufferStart += bufferPosition;

        bufferPosition = 0;

        bufferLength = numToCopy;

        newBuffer(newBuffer);

      }

    }

  }

  protected void newBuffer(byte[] newBuffer) {

    // Subclasses can do something here

    buffer = newBuffer;

  }

  /** Returns buffer size.  @see #setBufferSize */

  public int getBufferSize() {

    return bufferSize;

  }

  private void checkBufferSize(int bufferSize) {

    if (bufferSize <= 0)

      throw new IllegalArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")");

  }

  public void readBytes(byte[] b, int offset, int len) throws IOException {

    readBytes(b, offset, len, true);

  }

  /**

   * 读取流程如下:

   * 1.首先判断当前流的buffer中的信息是否可以满足当前的读取请求;

   * 2.如果可以满足,则从buffer中读取信息;读取工作结束;

   * 3.如果不可以满足,则将buffer中的剩余所用信息读取出来;

   * 4.当剩余信息读取完后,判断当前仍需读取的信息数量是否大于当前流的buffer的总容量

   * 5.如果大于,表明已经没有使用buffer的必要,因为当前它的缓冲信息功能已经不起作用了,直接通过子类的readInterval方法

   * 读取信息到指定位置

   * 6.如果小于,则再次填充buffer,读取剩余所需信息到指定位置

   */

  public void readBytes(byte[] b, int offset, int len, boolean useBuffer) throws IOException {

    if(len <= (bufferLength-bufferPosition)){

      // the buffer contains enough data to satisfy this request

      if(len>0) // to allow b to be null if len is 0...

        System.arraycopy(bufferbufferPosition, b, offset, len);

      bufferPosition+=len;

    } else {

      // the buffer does not have enough data. First serve all we've got.

      int available = bufferLength - bufferPosition;

      if(available > 0){

        System.arraycopy(bufferbufferPosition, b, offset, available);

        offset += available;

        len -= available;

        bufferPosition += available;

      }

      // and now, read the remaining 'len' bytes:

      if (useBuffer && len<bufferSize){

        // If the amount left to read is small enough, and

        // we are allowed to use our buffer, do it in the usual

        // buffered way: fill the buffer and copy from it:

        /**

         * 将缓存区域重新读满,

         * 供下次使用

         */

       refill();

       /**

        * 在bufferLength<len的情况下,表明已经读取到了文件的末尾还是无法满足len的要求

        * 这时需要抛出异常

        */

        if(bufferLength<len){

          // Throw an exception when refill() could not read len bytes:

          System.arraycopy(buffer, 0, b, offset, bufferLength);

          throw new IOException("read past EOF");

        } else {

          System.arraycopy(buffer, 0, b, offset, len);

          /**

           * 标示当前buffer读取的位数

           */

          bufferPosition=len;

        }

      } else {

       /**

        * 在buffer的大小也无法容纳剩下的所有数据时,

        * 就不需要使用缓存,直接将文件读入到bytes[]中

        * 

        */

        // The amount left to read is larger than the buffer

        // or we've been asked to not use our buffer -

        // there's no performance reason not to read it all

        // at once. Note that unlike the previous code of

        // this function, there is no need to do a seek

        // here, because there's no need to reread what we

        // had in the buffer.

        long after = bufferStart+bufferPosition+len;

        if(after > length())

          throw new IOException("read past EOF");

        readInternal(b, offset, len);

        bufferStart = after;

        bufferPosition = 0;

        bufferLength = 0;                    // trigger refill() on read

      }

    }

  }

  /**

   * 将文件中的信息读入到缓存中去

   * @throws IOException

   */

  private void refill() throws IOException {

    long start = bufferStart + bufferPosition;

    long end = start + bufferSize;

    if (end > length())   // don't read past EOF

      end = length();

    int newLength = (int)(end - start);

    if (newLength <= 0)

      throw new IOException("read past EOF");

    if (buffer == null) {

      newBuffer(new byte[bufferSize]);  // allocate buffer lazily

      seekInternal(bufferStart);

    }

    readInternal(buffer, 0, newLength);

    bufferLength = newLength;

    bufferStart = start;

    bufferPosition = 0;

  }

  /** Expert: implements buffer refill.  Reads bytes from the current position

   * in the input.

   * @param b the array to read bytes into

   * @param offset the offset in the array to start storing bytes

   * @param length the number of bytes to read

   */

  protected abstract void readInternal(byte[] b, int offset, int length)

          throws IOException;

  public long getFilePointer() { return bufferStart + bufferPosition; }

  public void seek(long pos) throws IOException {

    if (pos >= bufferStart && pos < (bufferStart + bufferLength))

      bufferPosition = (int)(pos - bufferStart);  // seek within buffer

    else {

      bufferStart = pos;

      bufferPosition = 0;

      bufferLength = 0;   // trigger refill() on read()

      seekInternal(pos);

    }

  }

  /** Expert: implements seek.  Sets current position in this file, where the

   * next {@link #readInternal(byte[],int,int)} will occur.

   * @see #readInternal(byte[],int,int)

   */

  protected abstract void seekInternal(long pos) throws IOException;

  public Object clone() {

    BufferedIndexInput clone = (BufferedIndexInput)super.clone();

    clone.buffer = null;

    clone.bufferLength = 0;

    clone.bufferPosition = 0;

    clone.bufferStart = getFilePointer();

    return clone;

  }

}

public void setBufferSize(int newSize)

这个函数是为了改变buffer的大小,默认buffer的大小为1KB

public void readBytes(byte[] b, int offset, int len, boolean useBuffer) throws IOException

这个函数描述了将文件中的信息写入到bytes中,在这个过程中借助了buffer的功能。

具体细节可以参考流程描述。

  评论这张
 
阅读(318)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017