Showing posts with label File handling. Show all posts
Showing posts with label File handling. Show all posts

Friday, 24 June 2011

Remember to properly close the File!

Today few comments on how to deal with Files, Streams, Connections and anything else that is ‘closeable’ in Java. To simplify we will focus on a FileWriter class and a simple code snippet with a bug that uses it:

public void writeToFile(String fileName, String content) {
try {
FileWriter file = new FileWriter(fileName);
file.write(content);
} catch (IOException e) {
// Log the exception
}
}

So what’s wrong? Well, plenty of things: we do not check the input values (maybe they are null or rubbish?), we do not care whether the file existed or is a directory, we do not care about specifying the encoding for the file. On the other hand you could argue that all of this are not problems but ‘features’, that the contract of this method says: just write using a FileWriter. That may be, but still there is one thing wrong with this code – we did not close the file.

Is that important? Well, yeah! Not closing the file may result in corrupted output of your write and makes the system still occupy the resources that could be freed. Always remember to close your Files, Streams, Connections! Let’s make a quick fix to the code and remove the bug:

public void writeToFile(String fileName, String content) {
try {
FileWriter file = new FileWriter(fileName);
file.write(content);
file.close();
} catch (IOException e) {
// Log the exception
}
}

Fixed? I guess some of you think it is fixed, but in fact it is not – what if there is an exception thrown during the write? The method will exit and the file will not be closed! Okay, there is a fix for that – use try/finally clause. This will guarantee that no matter what will happen in write the file will be closed.

public void writeToFile(String fileName, String content) {
FileWriter file = null;
try {
file = new FileWriter(fileName);
file.write(content);
} catch (IOException e) {
// Log the exception
} finally {
file.close();
}
}

Fixed? Well… no. The exception can be also thrown in the FileWriter constructor, so in finally block the file will be null. And this will result in NullPointerException. Let’s deal with that:

public void writeToFile(String fileName, String content) {
FileWriter file = null;
try {
file = new FileWriter(fileName);
file.write(content);
} catch (IOException e) {
// Log the exception
} finally {
if (file != null) {
file.close();
}
}
}

Done? Not yet… file.close() also can throw an exception! Since the method writeToFile does not allow any checked exception to be thrown, we have to deal with that also:

public void writeToFile(String fileName, String content) {
try {
FileWriter file = new FileWriter(fileName);
try {
file.write(content);
} finally {
file.close();
}
} catch (IOException e) {
// Log the exception
}
}

Finally (pun intended) we are done and the bug is fixed! Notice that in this code we did not had to check whether file is null before closing it – this is because the only way file is null is if an exception was thrown in the constructor in line 3 and this would lead to skipping most of the code and going to line 10. As you can see closing a closeable object is not a trivial task, so remember to do it properly!

There is another issue appearing in this problem – readability. If this the code above seems readable to you, then try to imagine dealing with more than one closeable object – it can get really messy! Therefore whenever you work with closeable objects it is a good idea to split the code into 2 methods: one that deals with exceptions and closing and the other which just does the main code. To see how this would work with the code above take a look at the following:

// Here we handle opening the file and manage exceptions.
public void writeToFile(String fileName, String content) {
try {
FileWriter file = new FileWriter(fileName);
try {
performWriteToFile(file, content);
} finally {
file.close();
}
} catch (IOException e) {
// Log the exception
}
}

// Here we perform all the operations on the file.
// This method usually is much longer.
private void performWriteToFile(FileWriter file,
String content) throws IOException {
file.write(content);
}


Tuesday, 10 May 2011

Moving file or directory from one directory to another

Here we write function to copy file or directory from one place to other.

public static boolean moveFileOrDirectory(String src, String dst){
File source = new File(src);
if(!source.exists())
return false;


File destination = new File(dest);
if(!destination.exists()){
System.out.print("Mentioned directory does not exist.
\nDo you want to create a new directory(Y/N)? "
);

String chk = readString();
if(chk.equals("Y") || chk.equals("y")){
destination.mkdir();
return copyDirectory(source, destination);
}else{
return false;
}
}else //if file or directory already exists, we have to copy and
//overwrite the already existing one
{
System.out.println("Given file or folder name already exists.
\nDo you want to replace now?"
);
String chk = readString();
if("Y".equals(chk) )
return copyDirectory(source, destination);
else return false;
}
}



 


Now this function makes use of copyDirectory function which can be written like this:



public static boolean copyDirectory(File sourceDir, File destDir) throws
IOException{

if(!destDir.exists()){
destDir.mkdir();
}

File[] children = sourceDir.listFiles();
for(File sourceChild : children){

String name = sourceChild.getName();

File destChild = new File(destDir, name);

if(sourceChild.isDirectory()){

return copyDirectory(sourceChild, destChild);

}

else{

return copyFile(sourceChild, destChild);

}

}

}



Now this in turn makes use of copyFile function.



public static void copyFile(File source, File dest) throws IOException{

if(!dest.exists()){

dest.createNewFile();

}

InputStream in = null;

OutputStream out = null;

try{

in = new FileInputStream(source);

out = new FileOutputStream(dest);

byte[] buf = new byte[1024];

int len;

while((len = in.read(buf)) > 0){

out.write(buf, 0, len);

}

}

finally{

in.close();

out.close();

}
return true;

}

Copy multiple files (java)

We have already seen the function to copy 1 file to another destination. Here we have to write function to copy multiple file to 1 location.

Refer this article for copyFile() function.

public static boolean copyMultipleFiles(String dst, String ... src){
for(String oneSrc : src)
{
boolean isCopied = copyFile(oneSrc,dst);
if(!isCopied)
return isCopied;
//Note that i have not yet figured out the case of rollback in case of
//unsuccessful copy of 1 file. Because this depends on your application.
//So if you want to rule out any copy if even 1 copy file fails,
//just call the delete function and so on.
}
return true;
}



Also note that this method uses varargs function, but you can use array instead.

Java - Copying one file to another

Here is function called copyFile  which takes 2 strings – source and destination. It copies source to destination.

 

private static void copyFile(String srcFile, String dstFile){

try{

File f1 = new File(srcFile);

File f2 = new File(dstFile);

InputStream in = new FileInputStream(f1);

//Append the file
OutputStream out = new FileOutputStream(f2,true);
//Overwrite the file.
OutputStream out = new FileOutputStream(f2);


byte[] buf = new byte[1024];

int len;

while ((len = in.read(buf)) > 0){

out.write(buf, 0, len);

}

in.close();

out.close();

System.out.println("File copied.");

}

catch(FileNotFoundException ex){

System.out.println(ex.getMessage() + " in
the specified directory."
);
return false;

}

catch(IOException e){

System.out.println(e.getMessage());
return false;

}
return true;
}

Rename the File or Directory in java

This example shows function, which renames the file or directory. The function takes old name and new name, and renames accordingly.

public boolean renameFile(String oldName, String newName)
{
File oldfile = new File(oldName);
if(!oldfile.exists())
{
System.out.println("File or directory does not exist.");
return false;
}
File newfile = new File(newName);
boolean reName = oldfile.renameTo(newfile);
if(!reName )
{
System.out.println("File or directory does not rename successfully.");
return reName ;
}else{
System.out.println("File or directory rename is successfully.");
return reName;
}
}

Create a File

For this createNewFile() method is used. It returns true if file is created and false otherwise. So for eg. it returns false if file already exist, so it can't create the new file here.

import java.io.*;
//now wherever you want do this:
public static void main(String[] args){
File file = new File("C://demo.txt");
boolean isCreated;
try
{
isCreated= file.createNewFile();
}
catch(IOException ioe)
{
System.out.println("Error in creating a new empty file :" + ioe);
}
}

Monday, 9 May 2011

Working with Directory tutorial

Following topics can be covered in this tutorial

How to Concatenate Files using SequenceInputStream

The SequenceInputStream(in the API reference documentation) creates a single input stream from multiple input sources. This example program uses SequenceInputStream to implement a concatenation utility that sequentially concatenates files together in the order they are listed on the command line.

So lets first create the Utility class which perform this application, say we call it ListOfFiles which takes list of file names in its constructor, and then concatenates them by creating a new InputStream for every filename listed as argument.

Creating the Utility Class

import java.util.*;
import java.io.*;

public class ListOfFiles implements Enumeration {

private String[] listOfFiles;
private int current = 0;

public ListOfFiles(String[] listOfFiles) {
this.listOfFiles = listOfFiles;
}

public boolean hasMoreElements() {
if (current < listOfFiles.length)
return true;
else
return false;
}

public Object nextElement() {
InputStream in = null;

if (!hasMoreElements())
throw new NoSuchElementException("No more files.");
else {
String nextElement = listOfFiles[current];
current++;
try {
in = new FileInputStream(nextElement);
} catch (FileNotFoundException e) {
System.err.println("ListOfFiles: Can't open " + nextElement);
}
}
return in;
}
}


ListOfFiles implements the Enumeration(in the API reference documentation) interface. You'll see how this comes into play as we walk through the rest of the program.


Using this Utility class


import java.io.*;

public class Concatenate {
public static void main(String[] args) throws IOException {
ListOfFiles mylist = new ListOfFiles(args);

SequenceInputStream s = new SequenceInputStream(mylist);
int c;

while ((c = s.read()) != -1)
System.out.write(c);

s.close();
}
}


After the main method creates the SequenceInputStream, it reads from it one byte at a time. When the SequenceInputStream needs an InputStream from a new source (such as for the first byte read or when it runs off the end of the current input stream), it calls nextElement on the Enumeration object to get the next InputStream. ListOfFiles creates FileInputStream objects lazily, meaning that whenever SequenceInputStream calls nextElement, ListOfFiles opens a FileInputStream on the next filename in the list and returns the stream. When the ListOfFiles runs out of files to read (it has no more elements), nextElement returns null, and the call to SequenceInputStream's read method returns -1 to indicate the end of input.

Concatenate simply echos all the data read from the SequenceInputStream to the standard output.

How to use file stream?


Monday, 25 April 2011

Java file as url

 A file can be read as URL with the java.net package. You must provide absolute path after the URI scheme name file://.
package com.demo.io;

import java.io.*;
import java.net.*;

public class FileAsURL {
public static void main(String[] args) throws Exception {
URL url = new URL("file:///tmp/com/demo/io/test.txt");
URLConnection conn = url.openConnection();
BufferedReader r = new BufferedReader(
new InputStreamReader(
conn.getInputStream()
)
);
String l = r.readLine();
while (l != null) {
System.out.println(l);
l = r.readLine();
}
}
}

Monday, 18 April 2011

A Java FileFilter example

The Filter File Java example code provides the following functionalities:
  • Filtering the files depending on the file extension provided by the user
  • User provides the file extension and then program lists all the matching files found
We can write our own file filter which implements FilenameFilter, so it has to implement accept method.

Example

class MyFilter implements FilenameFilter{

String ext;


public MyFilter(String ext){

this.ext="." + ext;
}


public boolean accept(File dir,String name){

return name.endsWith(ext);
}
}


So constructor takes argument as extenstion, which it has to filter.

Using our filter:

public class MyFilterUser{

public static void main(String args[]) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter the directory name : ");

String dir = in.readLine();

System.out.println("Please enter file type : ");

String extn = in.readLine();

File f = new File(dir);

FilenameFilter ff = new MyFilter(extn);

String s[] = f.list(ff);


for (int i = 0; i < s.length; i++){

System.out.println(s[i]);

}

}

}

Adding a filter to file chooser dialog

Eg. This is filter for .java files.
JFileChooser fileChooser = new JFileChooser(new File(filename));
fileChooser.addChoosableFileFilter(new MyFilter());

// Open file dialog.
fileChooser.showOpenDialog(frame);
openFile(fileChooser.getSelectedFile());

class MyFilter extends javax.swing.filechooser.FileFilter {
public boolean accept(File file) {
String filename = file.getName();
return filename.endsWith(".java");
}
public String getDescription() {
return "*.java";
}
}

How to display all the directories in a directory?

This function displays directories in a directory using filter.
public static void displayAllDir(String dirName) {
File dir = new File(dirName); //eg. C:
File[] files = dir.listFiles();
FileFilter fileFilter = new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
};
files = dir.listFiles(fileFilter);
System.out.println(files.length);
if (files.length == 0) {
System.out.println("Either dir does not exist
or is not a directory");
}
else {
for (int i=0; i< files.length; i++) {
File filename = files[i];
System.out.println(filename.toString());
}
}
}

How to display all the files in a directory ?

This function takes directory name and prints all files in it:

public static void displayAllDir(String dirName) {
File dir = new File(dirName); //eg. C:
String[] children = dir.list();
if (children == null) {
System.out.println( "Either dir does not exist or is
not a directory");
}
else {
for (int i=0; i< children.length; i++) {
String filename = children[i];
System.out.println(filename);
}
}
}

Displaying root directories in the system using java

This can be done using static method File.listRoots().

Eg.
File[] roots = File.listRoots();
System.out.println("Root directories :");
for (int i=0; i < roots.length; i++) {
System.out.println(roots[i].toString());
}

Finding the current working directory in java

The current directory can be found using getProperty() method.

String curDir = System.getProperty("user.dir");

How to traverse a directory in java?

This can be done by getting list of all children and then traversing further deep. See following function :

public static void traverseDirectory(File dir) {
System.out.println(dir);
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
traverseDirectory
(new File(dir, children[i]));
}
}
}

How to get the size of a directory in java?

This can be done with the help of FileUtils.sizeofDirectory(File Name) method of FileUtils class. This gives size in bytes.

import java.io.File;
import org.apache.commons.io.FileUtils;

public class GetDirSize {
public static void main(String[] args) {
long size = FileUtils.sizeOfDirectory
(new File("C:/Windows/Fonts"));
System.out.println("Size: " + size + " bytes");
}
}


How to search all files inside a directory using java?

This can be done using dir.list() method of File class.

File dir = new File("directoryName");
String[] children = dir.list();
if (children == null) {
System.out.println("does not exist or
is not a directory");
}
else {
for (int i = 0; i < children.length; i++) {
String filename = children[i];
System.out.println(filename);
}
}