/** * 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); } }