Monday, February 22, 2010

An auto-deleting FileInputStream

Sometimes, we need to read some data from a FileInputStream and, after reading it, delete the underlying file automatically by calling close(). This is not supported in java as of J2SE v1.6. However, we can achieve this by first calling close() on InputStream and then calling File.delete(). Something like:

File f = new File("c:\\xyz...");
FileInputStream fis = new FileInputStream(f);
//read from fis
...
...
fis.close();
f.delete();

Above works, but it is quite verbose, especially when we have to do this on multiple files. It becomes a chore. I present below a class which encapsulates this behavior in itself. We do not have to call f.delete() separately. Calling fis.close() will also delete the file automatically.

*** =========== ***

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
* A {@link FileInputStream} which (optionally) deletes the
* underlying file when the stream is closed.
*
* @author BJ
*/
public class AutoDeleteOnCloseFileInputStream extends FileInputStream{

private static final Logger log = Logger.getAnonymousLogger();

/**
* Underlying file object
*/
private File fileObj;



/**
* Flag to control auto-delete of file on close()
*/
private final boolean deleteOnClose;


/**
* Is underlying file stream closed. Becomes true after close()
* is invoked.
*/
private boolean isClosed;


/**
* Was underlying File object deleted.
*/
private boolean isDeleted;



/**
* Creates a fileInputStream wrapped around the given file and deletes the
* file when the FileInputStream is closed.
*
* @param file
*
* @throws FileNotFoundException
*/
public AutoDeleteOnCloseFileInputStream(File file)
throws FileNotFoundException {
this(file, true);
}


/**
* Creates a fileInputStream wrapped around the given file.
*
* @param file
* @param deleteOnClose
*
* @throws FileNotFoundException
*/
public AutoDeleteOnCloseFileInputStream(
final File file,
final boolean deleteOnClose) throws FileNotFoundException {
super(file);
this.fileObj = file;
this.deleteOnClose = deleteOnClose;
isClosed = false;
isDeleted = false;
}


/**
* @return boolean flag, true if the file should be deleted on close().
* Default is true.
*/
public final boolean isDeleteOnClose() {
return deleteOnClose;
}


/**
* @return is file deleted (after close)
*/
public boolean isDeleted() {
return isDeleted;
}


/**
* Closes the underlying FileInputStream and also deletes the
* file object from disk if, the isDeleteOnClose()
* is set to true.
*
* @see java.io.FileInputStream#close()
*/
@Override
public void close() {

if( isClosed ) {
log.finer("close()- already closed: "+ this);
return; //no-op
}


log.fine("close()- closing: "+ this);
isClosed = true;

try {
super.close();
if( isDeleteOnClose() ) {
isDeleted = fileObj.delete() ;
}
}
catch (IOException e) {
log.log(Level.WARNING, "Failed to close() stream: " + this, e);
}
catch (RuntimeException e) {
log.log(Level.WARNING, "Failed to delete(): " + fileObj, e);
}

log.info("close()- file [" + fileObj + "] deleted: "+ isDeleted);
fileObj = null;
}


@Override
public String toString() {

String defaultStr = super.toString();

try {
StringBuilder sb = new StringBuilder();
sb.append(defaultStr)
.append("{")
.append("File=").append(fileObj).append(", ")
.append("File size=").append(fileObj == null ? -1L : fileObj.length()).append(", ")
.append("deleteOnClose=").append(deleteOnClose).append(", ")
.append("isClosed=").append(isClosed).append(", ")
.append("isDeleted=").append(isDeleted)
.append("}");
return sb.toString();
}
catch(RuntimeException e){
log.log(Level.INFO, "Failed to stringify", e);
return defaultStr;
}
}


//For testing. Can be removed w/o any loss of functionality
public static void main(String[] args) throws IOException {
File f =File.createTempFile("temp_file", ".tmp");
FileInputStream fis = new AutoDeleteOnCloseFileInputStream(f);

System.out.println("*** Before close: " + fis);
System.out.println("Temp file exists: "+ f.exists());
fis.close();
System.out.println("*** After close: " + fis);
System.out.println("Temp file exists: "+ f.exists());
}
}



Here is the sample output, when this program is run:


** Before close: AutoDeleteOnCloseFileInputStream@42e816{File=C:\DOCUME~1\BIMALE~1\LOCALS~1\Temp\temp_file49625.tmp, File size=0, deleteOnClose=true, isClosed=false, isDeleted=false}
Temp file exists: true
Feb 22, 2010 2:24:34 PM AutoDeleteOnCloseFileInputStream close
INFO: close()- file [C:\DOCUME~1\BIMALE~1\LOCALS~1\Temp\temp_file49625.tmp] deleted: true
*** After close: AutoDeleteOnCloseFileInputStream@42e816{File=null, File size=-1, deleteOnClose=true, isClosed=true, isDeleted=true}
Temp file exists: false

Friday, February 12, 2010

Remove trailing white-spaces in Eclipse

Often, we need to quickly remove the trailing spaces (at the end) in the line. Eclipse does not come pre-configured with a shortcut for this in (java) editor perspective (I am using Europa release 3.3.2) . However, it is very easy to create one yourself, like following:

1. On menu choose Window -> Preferences ->General ->Keys
2. Filter the shortcuts for "remove"
3. Follow the image below. I have chosen ctrl+alt+backspace as shortcut key.

That is all you need. Now, while editing any source file, just hit the combo ctrl+alt+backspace to remove the (unnecessary) white-spaces from end of lines.