FileDocCategorySizeDatePackage
SharedFileInputStream.javaAPI DocJavaMail 1.4.316300Tue Nov 17 10:38:12 GMT 2009javax.mail.util

SharedFileInputStream

public class SharedFileInputStream extends BufferedInputStream implements SharedInputStream
A SharedFileInputStream is a BufferedInputStream that buffers data from the file and supports the mark and reset methods. It also supports the newStream method that allows you to create other streams that represent subsets of the file. A RandomAccessFile object is used to access the file data.

Note that when the SharedFileInputStream is closed, all streams created with the newStream method are also closed. This allows the creator of the SharedFileInputStream object to control access to the underlying file and ensure that it is closed when needed, to avoid leaking file descriptors. Note also that this behavior contradicts the requirements of SharedInputStream and may change in a future release.

author
Bill Shannon
since
JavaMail 1.4

Fields Summary
private static int
defaultBufferSize
protected RandomAccessFile
in
The file containing the data. Shared by all related SharedFileInputStreams.
protected int
bufsize
The normal size of the read buffer.
protected long
bufpos
The file offset that corresponds to the first byte in the read buffer.
protected long
start
The file offset of the start of data in this subset of the file.
protected long
datalen
The amount of data in this subset of the file.
private boolean
master
True if this is a top level stream created directly by "new". False if this is a derived stream created by newStream.
private SharedFile
sf
Constructors Summary
public SharedFileInputStream(File file)
Creates a SharedFileInputStream for the file.

param
file the file

	this(file, defaultBufferSize);
    
public SharedFileInputStream(String file)
Creates a SharedFileInputStream for the named file

param
file the file

	this(file, defaultBufferSize);
    
public SharedFileInputStream(File file, int size)
Creates a SharedFileInputStream with the specified buffer size.

param
file the file
param
size the buffer size.
exception
IllegalArgumentException if size <= 0.

	super(null);	// XXX - will it NPE?
        if (size <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
	init(new SharedFile(file), size);
    
public SharedFileInputStream(String file, int size)
Creates a SharedFileInputStream with the specified buffer size.

param
file the file
param
size the buffer size.
exception
IllegalArgumentException if size <= 0.

	super(null);	// XXX - will it NPE?
        if (size <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
	init(new SharedFile(file), size);
    
private SharedFileInputStream(SharedFile sf, long start, long len, int bufsize)
Used internally by the newStream method.

	super(null);
	this.master = false;
	this.sf = sf;
	this.in = sf.open();
	this.start = start;
	this.bufpos = start;
	this.datalen = len;
	this.bufsize = bufsize;
	buf = new byte[bufsize];
    
Methods Summary
public synchronized intavailable()
Returns the number of bytes that can be read from this input stream without blocking.

return
the number of bytes that can be read from this input stream without blocking.
exception
IOException if an I/O error occurs.

        ensureOpen();
	return (count - pos) + in_available();
    
public voidclose()
Closes this input stream and releases any system resources associated with the stream.

exception
IOException if an I/O error occurs.

        if (in == null)
            return;
	try {
	    if (master)
		sf.forceClose();
	    else
		sf.close();
	} finally {
	    sf = null;
	    in = null;
	    buf = null;
	}
    
private voidensureOpen()
Check to make sure that this stream has not been closed

	if (in == null)
	    throw new IOException("Stream closed");
    
private voidfill()
Fills the buffer with more data, taking into account shuffling and other tricks for dealing with marks. Assumes that it is being called by a synchronized method. This method also assumes that all data has already been read in, hence pos > count.

	if (markpos < 0) {
	    pos = 0;		/* no mark: throw away the buffer */
	    bufpos += count;
	} else if (pos >= buf.length)	/* no room left in buffer */
	    if (markpos > 0) {	/* can throw away early part of the buffer */
		int sz = pos - markpos;
		System.arraycopy(buf, markpos, buf, 0, sz);
		pos = sz;
		bufpos += markpos;
		markpos = 0;
	    } else if (buf.length >= marklimit) {
		markpos = -1;	/* buffer got too big, invalidate mark */
		pos = 0;	/* drop buffer contents */
		bufpos += count;
	    } else {		/* grow buffer */
		int nsz = pos * 2;
		if (nsz > marklimit)
		    nsz = marklimit;
		byte nbuf[] = new byte[nsz];
		System.arraycopy(buf, 0, nbuf, 0, pos);
		buf = nbuf;
	    }
        count = pos;
	in.seek(bufpos + pos);
	// limit to datalen
	int len = buf.length - pos;
	if (bufpos - start + pos + len > datalen)
	    len = (int)(datalen - (bufpos - start + pos));
	int n = in.read(buf, pos, len);
        if (n > 0)
            count = n + pos;
    
protected voidfinalize()
Force this stream to close.

	super.finalize();
	close();
    
public longgetPosition()
Return the current position in the InputStream, as an offset from the beginning of the InputStream.

return
the current position

//System.out.println("getPosition: start " + start + " pos " + pos + " bufpos " + bufpos + " = " + (bufpos + pos - start));
	if (in == null)
	    throw new RuntimeException("Stream closed");
	return bufpos + pos - start;
    
private intin_available()

	// XXX - overflow
	return (int)((start + datalen) - (bufpos + count));
    
private voidinit(javax.mail.util.SharedFileInputStream$SharedFile sf, int size)

	this.sf = sf;
	this.in = sf.open();
	this.start = 0;
	this.datalen = in.length();	// XXX - file can't grow
	this.bufsize = size;
	buf = new byte[size];
    
public synchronized voidmark(int readlimit)
See the general contract of the mark method of InputStream.

param
readlimit the maximum limit of bytes that can be read before the mark position becomes invalid.
see
#reset()

	marklimit = readlimit;
	markpos = pos;
    
public booleanmarkSupported()
Tests if this input stream supports the mark and reset methods. The markSupported method of SharedFileInputStream returns true.

return
a boolean indicating if this stream type supports the mark and reset methods.
see
java.io.InputStream#mark(int)
see
java.io.InputStream#reset()

	return true;
    
public java.io.InputStreamnewStream(long start, long end)
Return a new InputStream representing a subset of the data from this InputStream, starting at start (inclusive) up to end (exclusive). start must be non-negative. If end is -1, the new stream ends at the same place as this stream. The returned InputStream will also implement the SharedInputStream interface.

param
start the starting position
param
end the ending position + 1
return
the new stream

	if (in == null)
	    throw new RuntimeException("Stream closed");
	if (start < 0)
	    throw new IllegalArgumentException("start < 0");
	if (end == -1)
	    end = datalen;
	return new SharedFileInputStream(sf,
			this.start + (int)start, (int)(end - start), bufsize);
    
public synchronized intread(byte[] b, int off, int len)
Reads bytes from this stream into the specified byte array, starting at the given offset.

This method implements the general contract of the corresponding {@link java.io.InputStream#read(byte[], int, int) read} method of the {@link java.io.InputStream} class.

param
b destination buffer.
param
off offset at which to start storing bytes.
param
len maximum number of bytes to read.
return
the number of bytes read, or -1 if the end of the stream has been reached.
exception
IOException if an I/O error occurs.

        ensureOpen();
        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
	    throw new IndexOutOfBoundsException();
	} else if (len == 0) {
	    return 0;
	}

	int n = read1(b, off, len);
	if (n <= 0) return n;
	while ((n < len) /* && (in.available() > 0) */) {
	    int n1 = read1(b, off + n, len - n);
	    if (n1 <= 0) break;
	    n += n1;
	}
	return n;
    
public synchronized intread()
See the general contract of the read method of InputStream.

return
the next byte of data, or -1 if the end of the stream is reached.
exception
IOException if an I/O error occurs.

        ensureOpen();
	if (pos >= count) {
	    fill();
	    if (pos >= count)
		return -1;
	}
	return buf[pos++] & 0xff;
    
private intread1(byte[] b, int off, int len)
Read characters into a portion of an array, reading from the underlying stream at most once if necessary.

	int avail = count - pos;
	if (avail <= 0) {
	    if (false) {
	    /* If the requested length is at least as large as the buffer, and
	       if there is no mark/reset activity, do not bother to copy the
	       bytes into the local buffer.  In this way buffered streams will
	       cascade harmlessly. */
	    if (len >= buf.length && markpos < 0) {
		// XXX - seek, update bufpos - how?
		return in.read(b, off, len);
	    }
	    }
	    fill();
	    avail = count - pos;
	    if (avail <= 0) return -1;
	}
	int cnt = (avail < len) ? avail : len;
	System.arraycopy(buf, pos, b, off, cnt);
	pos += cnt;
	return cnt;
    
public synchronized voidreset()
See the general contract of the reset method of InputStream.

If markpos is -1 (no mark has been set or the mark has been invalidated), an IOException is thrown. Otherwise, pos is set equal to markpos.

exception
IOException if this stream has not been marked or if the mark has been invalidated.
see
#mark(int)

        ensureOpen();
	if (markpos < 0)
	    throw new IOException("Resetting to invalid mark");
	pos = markpos;
    
public synchronized longskip(long n)
See the general contract of the skip method of InputStream.

param
n the number of bytes to be skipped.
return
the actual number of bytes skipped.
exception
IOException if an I/O error occurs.

        ensureOpen();
	if (n <= 0) {
	    return 0;
	}
	long avail = count - pos;
     
        if (avail <= 0) {
            // If no mark position set then don't keep in buffer
	    /*
            if (markpos <0) 
                return in.skip(n);
	    */
            
            // Fill in buffer to save bytes for reset
            fill();
            avail = count - pos;
            if (avail <= 0)
                return 0;
        }
        
        long skipped = (avail < n) ? avail : n;
        pos += skipped;
        return skipped;