/**
* Copyright (C) 2009 Future Invent Informationsmanagement GmbH. All rights
* reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*/
package org.fuin.utils4j;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
/**
* A random access based file output stream.
*/
public class RandomAccessFileOutputStream extends OutputStream {
private final RandomAccessFile file;
private long counter = 0;
/**
* Constructor with file.
*
* @param file
* File the stream operates on - Cannot be null
.
* @param mode
* Access mode, as described in RandomAccessFile
-
* Cannot be null
.
*
* @throws FileNotFoundException
* If the mode is "r" but the given file object does not denote
* an existing regular file, or if the mode begins with "rw" but
* the given file object does not denote an existing, writable
* regular file and a new regular file of that name cannot be
* created, or if some other error occurs while opening or
* creating the file.
*/
public RandomAccessFileOutputStream(final File file, final String mode)
throws FileNotFoundException {
super();
Utils4J.checkNotNull("file", file);
Utils4J.checkNotNull("mode", mode);
this.file = new RandomAccessFile(file, mode);
}
/**
* Constructor with output stream. The new stream shares the
* RandomAccessFile
with the argument. Be aware that closing
* this stream will also close the file used by the argument!
*
* @param out
* The RandomAccessFile
instance from this argument
* will be used - Cannot be null
.
*/
public RandomAccessFileOutputStream(final RandomAccessFileOutputStream out) {
super();
Utils4J.checkNotNull("out", out);
file = out.getRandomAccessFile();
}
/**
* Constructor with input stream. The new stream shares the
* RandomAccessFile
with the argument. Be aware that closing
* this stream will also close the file used by the argument!
*
* @param in
* The RandomAccessFile
instance from this argument
* will be used - Cannot be null
.
*/
public RandomAccessFileOutputStream(final RandomAccessFileInputStream in) {
super();
Utils4J.checkNotNull("in", in);
file = in.getRandomAccessFile();
}
/**
* Writes the specified byte to this file. The write starts at the current
* file pointer.
*
* @param b
* the byte
to be written.
*
* @exception IOException
* if an I/O error occurs.
*/
public final void write(final int b) throws IOException {
file.write(b);
counter++;
}
/**
* Writes b.length
bytes from the specified byte array to this
* file, starting at the current file pointer.
*
* @param b
* the data.
*
* @exception IOException
* if an I/O error occurs.
*/
public final void write(final byte[] b) throws IOException {
file.write(b);
counter = counter + b.length;
}
/**
* Writes len
bytes from the specified byte array starting at
* offset off
to the file.
*
* @param b
* the data.
* @param off
* the start offset in the data.
* @param len
* the number of bytes to write.
*
* @exception IOException
* If an I/O error occurs.
*/
public final void write(final byte[] b, final int off, final int len) throws IOException {
file.write(b, off, len);
counter = counter + len;
}
/**
* Calls sync()
of the underlying file's descriptor.
*
* @throws IOException
* If an I/O error occurs.
*/
public final void flush() throws IOException {
file.getChannel().force(true);
}
/**
* Closes the underlying file and sets the length to the current position.
*
* @throws IOException
* If an I/O error occurs.
*/
public final void close() throws IOException {
file.close();
}
/**
* Returns the channel used by the random access file.
*
* @return Channel.
*/
public final FileChannel getChannel() {
return file.getChannel();
}
/**
* Returns the underlying file.
*
* @return Random access file.
*/
final RandomAccessFile getRandomAccessFile() {
return file;
}
/**
* Sets the file-pointer offset, measured from the beginning of this file,
* at which the next read or write occurs. The offset may be set beyond the
* end of the file. Setting the offset beyond the end of the file does not
* change the file length. The file length will change only by writing after
* the offset has been set beyond the end of the file.
*
* @param pos
* the offset position, measured in bytes from the beginning of
* the file, at which to set the file pointer.
*
* @exception IOException
* if pos
is less than 0
or if an
* I/O error occurs.
*/
public final void seek(final long pos) throws IOException {
file.seek(pos);
}
/**
* Sets the length of this file.
*
* @param newLength
* The desired length of the file
*
* @exception IOException
* If an I/O error occurs
*/
public final void setLength(final long newLength) throws IOException {
file.setLength(newLength);
}
/**
* Sets the internal counter to 0
.
*/
public final void resetCounter() {
counter = 0;
}
/**
* Returns the number of bytes written since start or since last call to
* resetCounter()
.
*
* @return Number of bytes written.
*/
public final long getCounter() {
return counter;
}
/**
* Sets the length of the file to the number of written bytes. This is the
* same as calling setLength(getCounter())
.
*
* @throws IOException
* Error setting the file length.
*/
public final void truncate() throws IOException {
file.setLength(counter);
}
/**
* Lock the file.
*
* @param tryLockMax
* Number of tries to lock before throwing an exception.
* @param tryWaitMillis
* Milliseconds to sleep between retries.
*
* @return FileLock.
*
* @throws LockingFailedException
* Locking the file failed.
*/
public final FileLock lock(final int tryLockMax, final long tryWaitMillis)
throws LockingFailedException {
return Utils4J.lockRandomAccessFile(file, tryLockMax, tryWaitMillis);
}
}