/*
* This code 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 2.1 of the License, or (at your option) any later version.
*
* This code 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 program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
package no.geosoft.cc.io;
import java.io.*;
import java.nio.channels.*;
import java.util.zip.*;
/**
* Base class for file accessors (file readers and writers).
*
* <p>
* Features:
* <ul>
* <li>Logging</li>
* <li>Progress monitoring</li>
* <li>ASCII and binary</li>
* <li>Checksum generation</li>
* </ul>
*
* <p>
* This class is not abstract as a subclass will overload only one of
* readFile() and writeFile() depending wether it is a reader or a writer
* class (it can only be one of the two).
*
* <p>
* There are some convenience methods for actually accessing the files
* (readLine() and write()), for more detailed access a reader class
* will use the reader_/binaryReader_ and a writer will use the
* writer/binaryWriter_ objects.
*
* @author <a href="mailto:info@geosoft.no">GeoSoft</a>
*/
public class FileAccessor
{
protected File file_;
protected Object stream_; // InputStream or OutputStream
protected BufferedReader reader_;
protected BufferedWriter writer_;
protected DataInputStream binaryReader_;
protected DataOutputStream binaryWriter_;
protected FileLogger logger_;
protected int lineNo_;
protected Checksum checksum_;
private FileChannel fileChannel_;
/**
* Create a file accessor for the specified file and with the
* specified logger instance.
*
* @param file File to create accessor for.
* @param logger Logger.
*/
public FileAccessor (File file, FileLogger logger)
{
file_ = file;
stream_ = null;
reader_ = null;
writer_ = null;
binaryReader_ = null;
binaryWriter_ = null;
setLogger (logger);
}
/**
* Create a file accessor without a logger.
*
* @param file File to create accessor for.
*/
public FileAccessor (File file)
{
this (file, null);
}
/**
* Set logger.
*
* @param logger File accessor logger.
*/
public void setLogger (FileLogger logger)
{
logger_ = logger == null ? new DefaultLogger() : logger;
}
/**
* Open file for reading.
*/
protected void openForRead()
{
logger_.log (FileLogger.INFO, 0, 0, "Open", file_);
logger_.reportProgress (file_, 0);
checksum_ = new Adler32();
try {
FileInputStream fileStream = new FileInputStream (file_);
fileChannel_ = fileStream.getChannel();
InputStream stream = new CheckedInputStream (fileStream, checksum_);
reader_ = new BufferedReader (new InputStreamReader (stream));
binaryReader_ = new DataInputStream (new BufferedInputStream (stream));
lineNo_ = -1;
stream_ = stream;
}
catch (IOException exception) {
exception.printStackTrace();
logger_.log (FileLogger.ERROR, 0, 0, "UnableToOpen", file_);
}
}
/**
* Open file for writing.
*/
protected void openForWrite()
{
logger_.log (FileLogger.INFO, 0, 0, "Open", file_);
logger_.reportProgress (file_, 0);
checksum_ = new Adler32();
try {
FileOutputStream fileStream = new FileOutputStream (file_);
fileChannel_ = fileStream.getChannel();
OutputStream stream = new CheckedOutputStream (fileStream, checksum_);
writer_ = new BufferedWriter (new OutputStreamWriter (stream));
binaryWriter_ = new DataOutputStream (new BufferedOutputStream (stream));
stream_ = stream;
}
catch (IOException exception) {
exception.printStackTrace();
logger_.log (FileLogger.ERROR, 0, 0, "UnableToOpen", file_);
}
}
/**
* Check if the entire file has been read.
*
* @return True if the entire file has been read, false otherwise.
*/
protected boolean isDone()
{
return getPosition() == file_.length();
}
/**
* Close streams.
*/
protected void close()
{
try {
if (writer_ != null) writer_.flush();
if (stream_ instanceof OutputStream) {
OutputStream stream = (OutputStream) stream_;
stream.flush();
stream.close();
}
else {
InputStream stream = (InputStream) stream_;
stream.close();
}
}
catch (Exception exception) {
logger_.log (FileLogger.ERROR, 0, 0, "UnableToClose", file_);
}
logger_.reportProgress (file_, (int) file_.length());
reader_ = null;
writer_ = null;
binaryReader_ = null;
binaryWriter_ = null;
stream_ = null;
}
/**
* Return the checksum for this file.
*
* @return Checksum for this file.
*/
public long getChecksum()
{
return checksum_.getValue();
}
/**
* Return current file position.
*
* @return Current file position.
*/
protected long getPosition()
{
long position = 0;
try {
position = fileChannel_.position();
}
catch (Exception exception) {
}
return position;
}
/**
* Read one line from the file.
*
* @return Next line from the file (or null if done or an error
* occured).
*/
public String readLine()
throws IOException
{
if (reader_ == null) return null;
String line = reader_.readLine();
lineNo_++;
reportProgress();
return line;
}
/**
* Write a line to the file.
*
* @param string Line to write.
*/
public void write (String string)
throws IOException
{
if (writer_ == null) return;
writer_.write (string, 0, string.length());
reportProgress();
}
/**
* Skip n bytes during read.
*
* @param n Number of bytes to skip.
*/
public void skip (long n)
throws IOException
{
if (reader_ != null) reader_.skip (n);
else if (binaryReader_ != null) binaryReader_.skipBytes ((int) n);
reportProgress();
}
/**
* Force the progress to be reported to the logger.
*/
public void reportProgress()
{
logger_.reportProgress (file_, (int) getPosition());
}
/**
* To be overridden by a file reader class.
*
* @return File content as some java object.
*/
public Object readFile()
{
return null;
}
/**
* To be overridden by a file writer class.
*
* @param object Object to write.
*/
public void writeFile (Object object)
{
}
/**
* Dummy logger instance in case none is specified.
*/
public class DefaultLogger implements FileLogger
{
public void log (int type, int lineNo, int columnNo, String message,
Object object)
{
// Debgugging
System.out.println (lineNo + "," + columnNo + ": " + message +
": " + object.toString());
}
public void reportProgress (File file, int amount)
{
}
}
}