Java Read and Write Files

Java provides a number of classes and methods that allow you to read from and write to the files.

The purpose of this chapter is to introduce the basic techniques that read from and write to a file. Although bytes streams are used, these techniques can be adapted to character-based streams.

Two of the most often-used stream classes are FileInputStream and FileOutputStream, which create byte streams linked to the files. To open a file, you simply create an object of one of these classes, specifying the name of file as an argument to the constructor. Although both the classes support additional constructors, the following are the forms that we will be using :

FileInputStream(String fileName) throws FileNotFoundException)
FileOutputStream(String fileName) throws FileNotFoundException

Here, fileName specifies the name of the file that you want to open. When you create an input stream, if the file does not exist, then FileNotFoundException is thrown. For output streams, if the file can't be opened or created, then FileNotFoundException is thrown. FileNotFoundException is a subclass of IOException. When an output file is opened, any pre-existing file by the same name is destroyed.

When you are done with a file, you must close it. this is done by calling the close() method, which is implemented by both FileInputStream and FileOutputStream. It is shown below :

void close() throws IOException

Closing a file releases the system resources allocated to the file, allowing them to be used by another file. Failure to close a file can result in "memory leaks" because of unused resources remaining allocated.

Before moving on, it is important to point out that there are two basic approaches that you can use to close a file when you are done with it. The first is the traditional approach, in which the close() method is called explicitly when the file is no longer needed. This is the approach used by all the versions of Java prior to JDK 7 and is, therefore, found in all the pre-JDK 7 legacy code. The second is to use the try-with-resources statement added by JDK 7, which automatically closes a file when it is no longer needed. In this approach, no explicit call to close() is executed. Since there is a large amount of pre-JDK 7 legacy code that is still being used and maintained, it is important that you know and understand the traditional approach. Therefore, we will begin with it.

To read from a file, you can use a version of the read() method that is defined within the FileInputStream. The one that we will use is shown below :

int read() throws IOException

Each time that it is called, it reads a single byte from the file and returns the byte as an integer value. The read() returns -1 when the end of the file is encountered. It can throw an IOException.

Read and Display the Contents of File in Java

The following program uses read() method to input and display the contents of a file that contains ASCII text. The name of the file is specified as a command-line argument.

/* Java Program Example - Java Read and Write File
 * This program use read() to input and display the 
 * file's content.
 * 
 * Display a text file.
 * To use this program, specify the name of the 
 * file that you want to see.
 * For example, to see a file called DEMO.TXT, 
 * use the following command line
 * 
 * java FileOperationDemo DEMO.TXT
 */

import java.io.*;

class FileOperationDemo
{
    public static void main(String args[])
    {
        
        int i;
        FileInputStream fin;
        
        /* first, confirm that a filename has been
         * specified 
    */
         if(args.length != 1)
         {
             System.out.println("Usage : FileOperationDemo filename");
             return;
         }
         
         /* now attempt to open the file */
         try
         {
             fin = new FileInputStream(args[0]);
         }
         catch(FileNotFoundException e)
         {
             System.out.println("Cannot Open the File..!!");
             return;
         }
         
         /* at this point, the file is open and can be read
          * The following reads characters until EOF is encountered  
          */
          try
          {
              do
              {
                  i = fin.read();
                  
                  if(i != -1)
                    System.out.print((char) i);
                    
              }while(i != -1);
          }
          catch(IOException e)
          {
              System.out.println("Error in Reading File..!!");
          }
          
          /* now close the file */
          try
          {
              fin.close();
          }
          catch(IOException e)
          {
              System.out.println("Error in Closing the File..!!");
          }
          
    }
}

In this program, notice the try/catch blocks that handle the I/O errors that might occur. Each I/O operation is monitored for exceptions, and if an exception occurs, it is handled. Be aware that in simple programs or example code, it is common to see I/O exceptions simply thrown out of the main(), as was done in the earlier console I/O examples.

Also, in some real-world code, it can be helpful to let an exception propagate to a calling routine to let the caller know that an I/O operation failed.

Although the preceding example closes the file stream after the file is read, there is a variation that is often useful. The variation is to call the close() method within a finally block. In this approach, all of the methods that access the file are contained within a try block, and finally block is used to close the file. This way, no matter how the try block terminates, the file is closed. Assuming the preceding example, below is how the try block that reads the file can be recoded :

try {
    do 
    {
    i = fin.read();
    
    if(i != -1)
      System.out.print((char) i);
      
   } while(i != -1);
   
} catch(IOException e)
 {
      System.out.println("Error in Reading the File..!!");
 }
 
finally {
   /* close file on the way out of the try block */
   try {
      fin.close();
     
   } catch(IOException e) {
   System.out.println("Error in Closing the File..!!");
   }
}

Although not an issue in this case, one advantage to this approach in general is that if the code that accesses a file terminates because of some non-I/O related exception, the file still closed by the finally block.

Sometimes it is easier to wrap the portions of a program that open the file and access the file within a single try block rather than separating two and then use a finally block to close the file. For example, below is another way to write FileOperationDemo program:

/* Java Program Example - Java Read and Write File
 * 
 * Display a text file.
 * To use this program, specify the name of the 
 * file that you want to see.
 * For example, to see a file called DEMO.TXT, 
 * use the following command line
 * 
 * java FileOperationDemo DEMO.TXT
 * 
 * This variation wraps the code that opens and accesses
 * the file within a single try block.
 * The file is closed by the finally block
 */

import java.io.*;

class FileOperationDemo
{
    public static void main(String args[])
    {
        
        int i;
        FileInputStream fin = null;
        
        /* first, confirm that a filename has been specified  */
         if(args.length != 1)
         {
             System.out.println("Usage : FileOperationDemo filename");
             return;
         }
         
         /* The following code opens a file, reads characters until 
          * EOF is encountered, and then closes the file via the 
          * finally block          */
          try {
              fin = new FileInputStream(args[0]);
              
              do {
                  i = fin.read();
                  if(i != -1)
                    System.out.println((char) i);
              } while(i != -1);
              
         } catch(FileNotFoundException e) {
              System.out.println("File Not Found..!!");
         } catch(IOException e) {
             System.out.println("An I/O Error Occurred..!!");
         } finally {
             /* close the file in all cases */
             try {
                 if(fin != null)
                    fin.close();
             } catch(IOException e) {
                 System.out.println("Error in Closing the File..!!");
             }
         }
         
    }
}

In this approach, notice that fin is initialized to null. Then, in finally block, the file is closed only if fin is not null. This works because fin will be non-null only if the file is successfully opened. Thus, close() is not called if an exception occurs while opening the file.

It is possible to make the try/catch sequence in the preceding example a bit more compact. Because FileNotFoundException is a subclass of IOException, it need not be caught separately. For example, below is the sequence recoded to eliminate catching FileNotFoundException. In this case, the standard exception message, which describes the error, is displayed.

try {
    fin = new FileInputStream(args[0]);
    
    do {
        i = fin.read();
        if(i != -1)
            System.out.print((char) i);
       } while(i != -1);
       
} catch(IOException e) {
    System.out.println("I/O Error : " + e);
} finally {
    /* close the file in all cases */
    try {
        if(fin != null)
            fin.close();
    } catch(IOException e) {
        System.out.println("Error in Closing the File..!!");
    }
}

In this approach, any error, including an error opening the file, is simply handled by single catch statement. Be aware, however, this approach is not appropriate in the cases in which you want to deal separately with a failure to open a file, such as might be cause if a user mistypes a filename. In such a situation, you might want to prompt for the correct name, for example, before entering a try block that accesses the file.

To write a file, you can use the write() method defined by the FileOutputStream. Its simplest form is shown below :

void write(int byteval) throws IOException

This method writes the byte specified by byteval to the file. Although byteval is declared as an integer, only the low-order eight bits are written to the file. If an error occurs during writing, an IOException is thrown.

Copy Files in Java

The following example uses the write() method to copy a file :

/* Java Program Example - Java Read and Write Files
 * Copy a file.
 * To use this program, specify the name of the source 
 * file and the destination file.
 * For example, to copy a file called FIRST.TXT to 
 * a file called SECOND.TXT, use the following 
 * command line.
 * 
 * java FileOperationDemo FIRST.TXT SECOND.TXT
 */

import java.io.*;

class FileOperationDemo
{
    public static void main(String args[]) throws IOException
    {
        
        int i;
        FileInputStream fin = null;
        FileOutputStream fout = null;
        
        /* first, confirm that both files have been specified */
        if(args.length != 2) {
            System.out.println("Usage : FileOperationDemo from to");
            return;
        }
        
        /* copy a file */
        try {
            /* now attempt to open the files */
            fin = new FileInputStream(args[0]);
            fout = new FileOutputStream(args[1]);
            
            do {
                i = fin.read();
                if(i != -1)
                    fout.write(i);
            } while(i != -1);
            
        } catch(IOException e) {
            System.out.println("I/O Error : " + e);
        } finally {
            try {
                if(fin != null)
                    fin.close();
            } catch(IOException e2) {
                System.out.println("Error Closing the Input File..!!");
            }
            try {
                if(fout != null)
                    fout.close();
            } catch(IOException e2) {
                System.out.println("Error Closing the Output File..!!");
            }
        }
        
    }
}

In this program, notice that the two separate try blocks are used when closing the files. This ensures that both the files are closed, even if the call to the fin.close() throws an exception.

In general, notice that all the potential I/O errors are handled in the preceding two programs by the use of exceptions. This differs from some computer languages that use error codes to report file errors. Not only do exceptions make file handling cleaner, but they also enable Java to easily differentiate the end-of-file condition from file errors when input is being performed.

Examples on Files in Java

Here are some examples related to files in Java, you can go for.

Java Online Test


« Previous Tutorial Next Tutorial »