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 }