View Javadoc

    1   /* RandomAccessInputStream
    2   *
    3   * Created on May 21, 2004
    4   *
    5   * Copyright (C) 2004 Internet Archive.
    6   *
    7   * This file is part of the Heritrix web crawler (crawler.archive.org).
    8   *
    9   * Heritrix is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU Lesser Public License as published by
    11  * the Free Software Foundation; either version 2.1 of the License, or
    12  * any later version.
    13  *
    14  * Heritrix is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU Lesser Public License for more details.
    18  *
    19  * You should have received a copy of the GNU Lesser Public License
    20  * along with Heritrix; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    22  */
    23  package org.archive.io;
    24
    25
    26  import java.io.File;
    27  import java.io.IOException;
    28  import java.io.RandomAccessFile;
    29
    30
    31  /***
    32   * Wraps a RandomAccessFile with an InputStream interface.
    33   *
    34   * @author gojomo
    35   */
    36  public class RandomAccessInputStream extends SeekInputStream {
    37
    38      /***
    39       * Reference to the random access file this stream is reading from.
    40       */
    41      private RandomAccessFile raf = null;
    42
    43      /***
    44       * When mark is called, save here the current position so we can go back
    45       * on reset.
    46       */
    47      private long markpos = -1;
    48
    49      /***
    50       * True if we are to close the underlying random access file when this
    51       * stream is closed.
    52       */
    53      private boolean sympathyClose;
    54
    55      /***
    56       * Constructor.
    57       *
    58       * If using this constructor, caller created the RAF and therefore
    59       * its assumed wants to control close of the RAF.  The RAF.close
    60       * is not called if this constructor is used on close of this stream.
    61       *
    62       * @param raf RandomAccessFile to wrap.
    63       * @throws IOException
    64       */
    65      public RandomAccessInputStream(RandomAccessFile raf)
    66      throws IOException {
    67          this(raf, false, 0);
    68      }
    69
    70      /***
    71       * Constructor.
    72       *
    73       * @param file File to get RAFIS on.  Creates an RAF from passed file.
    74       * Closes the created RAF when this stream is closed.
    75       * @throws IOException
    76       */
    77      public RandomAccessInputStream(final File file)
    78      throws IOException {
    79          this(new RandomAccessFile(file, "r"), true, 0);
    80      }
    81
    82      /***
    83       * Constructor.
    84       *
    85       * @param file File to get RAFIS on.  Creates an RAF from passed file.
    86       * Closes the created RAF when this stream is closed.
    87       * @param offset
    88       * @throws IOException
    89       */
    90      public RandomAccessInputStream(final File file, final long offset)
    91      throws IOException {
    92          this(new RandomAccessFile(file, "r"), true, offset);
    93      }
    94
    95      /***
    96       * @param raf RandomAccessFile to wrap.
    97       * @param sympathyClose Set to true if we are to close the RAF
    98       * file when this stream is closed.
    99       * @param offset
    100      * @throws IOException
    101      */
    102     public RandomAccessInputStream(final RandomAccessFile raf,
    103             final boolean sympathyClose, final long offset)
    104     throws IOException {
    105         super();
    106         this.sympathyClose = sympathyClose;
    107         this.raf = raf;
    108         if (offset > 0) {
    109             this.raf.seek(offset);
    110         }
    111     }
    112
    113     /* (non-Javadoc)
    114      * @see java.io.InputStream#read()
    115      */
    116     public int read() throws IOException {
    117         return this.raf.read();
    118     }
    119
    120     /* (non-Javadoc)
    121      * @see java.io.InputStream#read(byte[], int, int)
    122      */
    123     public int read(byte[] b, int off, int len) throws IOException {
    124         return this.raf.read(b, off, len);
    125     }
    126
    127     /* (non-Javadoc)
    128      * @see java.io.InputStream#read(byte[])
    129      */
    130     public int read(byte[] b) throws IOException {
    131         return this.raf.read(b);
    132     }
    133
    134     /* (non-Javadoc)
    135      * @see java.io.InputStream#skip(long)
    136      */
    137     public long skip(long n) throws IOException {
    138         this.raf.seek(this.raf.getFilePointer() + n);
    139         return n;
    140     }
    141
    142 	public long position() throws IOException {
    143 		return this.raf.getFilePointer();
    144 	}
    145
    146 	public void position(long position) throws IOException {
    147 		this.raf.seek(position);
    148 	}
    149
    150 	public int available() throws IOException {
    151         long amount = this.raf.length() - this.position();
    152         return (amount >= Integer.MAX_VALUE)? Integer.MAX_VALUE: (int)amount;
    153 	}
    154
    155     public boolean markSupported() {
    156         return true;
    157     }
    158
    159     public synchronized void mark(int readlimit) {
    160         try {
    161             this.markpos = position();
    162         } catch (IOException e) {
    163             // Set markpos to -1. Will cause exception reset.
    164             this.markpos = -1;
    165         }
    166     }
    167
    168     public synchronized void reset() throws IOException {
    169         if (this.markpos == -1) {
    170             throw new IOException("Mark has not been set.");
    171         }
    172         position(this.markpos);
    173     }
    174
    175     public void close() throws IOException {
    176         try {
    177             super.close();
    178         } finally {
    179             if (this.sympathyClose) {
    180                 this.raf.close();
    181             }
    182         }
    183     }
    184 }