001: /* RandomAccessInputStream
002: *
003: * Created on May 21, 2004
004: *
005: * Copyright (C) 2004 Internet Archive.
006: *
007: * This file is part of the Heritrix web crawler (crawler.archive.org).
008: *
009: * Heritrix is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU Lesser Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * any later version.
013: *
014: * Heritrix is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: * GNU Lesser Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser Public License
020: * along with Heritrix; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: */
023: package org.archive.io;
024:
025: import java.io.File;
026: import java.io.IOException;
027: import java.io.RandomAccessFile;
028:
029: /**
030: * Wraps a RandomAccessFile with an InputStream interface.
031: *
032: * @author gojomo
033: */
034: public class RandomAccessInputStream extends SeekInputStream {
035:
036: /**
037: * Reference to the random access file this stream is reading from.
038: */
039: private RandomAccessFile raf = null;
040:
041: /**
042: * When mark is called, save here the current position so we can go back
043: * on reset.
044: */
045: private long markpos = -1;
046:
047: /**
048: * True if we are to close the underlying random access file when this
049: * stream is closed.
050: */
051: private boolean sympathyClose;
052:
053: /**
054: * Constructor.
055: *
056: * If using this constructor, caller created the RAF and therefore
057: * its assumed wants to control close of the RAF. The RAF.close
058: * is not called if this constructor is used on close of this stream.
059: *
060: * @param raf RandomAccessFile to wrap.
061: * @throws IOException
062: */
063: public RandomAccessInputStream(RandomAccessFile raf)
064: throws IOException {
065: this (raf, false, 0);
066: }
067:
068: /**
069: * Constructor.
070: *
071: * @param file File to get RAFIS on. Creates an RAF from passed file.
072: * Closes the created RAF when this stream is closed.
073: * @throws IOException
074: */
075: public RandomAccessInputStream(final File file) throws IOException {
076: this (new RandomAccessFile(file, "r"), true, 0);
077: }
078:
079: /**
080: * Constructor.
081: *
082: * @param file File to get RAFIS on. Creates an RAF from passed file.
083: * Closes the created RAF when this stream is closed.
084: * @param offset
085: * @throws IOException
086: */
087: public RandomAccessInputStream(final File file, final long offset)
088: throws IOException {
089: this (new RandomAccessFile(file, "r"), true, offset);
090: }
091:
092: /**
093: * @param raf RandomAccessFile to wrap.
094: * @param sympathyClose Set to true if we are to close the RAF
095: * file when this stream is closed.
096: * @param offset
097: * @throws IOException
098: */
099: public RandomAccessInputStream(final RandomAccessFile raf,
100: final boolean sympathyClose, final long offset)
101: throws IOException {
102: super ();
103: this .sympathyClose = sympathyClose;
104: this .raf = raf;
105: if (offset > 0) {
106: this .raf.seek(offset);
107: }
108: }
109:
110: /* (non-Javadoc)
111: * @see java.io.InputStream#read()
112: */
113: public int read() throws IOException {
114: return this .raf.read();
115: }
116:
117: /* (non-Javadoc)
118: * @see java.io.InputStream#read(byte[], int, int)
119: */
120: public int read(byte[] b, int off, int len) throws IOException {
121: return this .raf.read(b, off, len);
122: }
123:
124: /* (non-Javadoc)
125: * @see java.io.InputStream#read(byte[])
126: */
127: public int read(byte[] b) throws IOException {
128: return this .raf.read(b);
129: }
130:
131: /* (non-Javadoc)
132: * @see java.io.InputStream#skip(long)
133: */
134: public long skip(long n) throws IOException {
135: this .raf.seek(this .raf.getFilePointer() + n);
136: return n;
137: }
138:
139: public long position() throws IOException {
140: return this .raf.getFilePointer();
141: }
142:
143: public void position(long position) throws IOException {
144: this .raf.seek(position);
145: }
146:
147: public int available() throws IOException {
148: long amount = this .raf.length() - this .position();
149: return (amount >= Integer.MAX_VALUE) ? Integer.MAX_VALUE
150: : (int) amount;
151: }
152:
153: public boolean markSupported() {
154: return true;
155: }
156:
157: public synchronized void mark(int readlimit) {
158: try {
159: this .markpos = position();
160: } catch (IOException e) {
161: // Set markpos to -1. Will cause exception reset.
162: this .markpos = -1;
163: }
164: }
165:
166: public synchronized void reset() throws IOException {
167: if (this .markpos == -1) {
168: throw new IOException("Mark has not been set.");
169: }
170: position(this .markpos);
171: }
172:
173: public void close() throws IOException {
174: try {
175: super.close();
176: } finally {
177: if (this.sympathyClose) {
178: this.raf.close();
179: }
180: }
181: }
182: }
|