Chapter 11: File Input and Output



File and FileDialog Objects

A File in Java (see API reference) is an object that represents a file or a directory. You can create a File object that will be associated with a file named "stuff.dat":

File myFile = new File ("stuff.dat");

Note, you will need to import the package java.io:

import java.io.*;

This assumes that the file stuff.dat is (or will be) located in the current working directory. If this file is located elsewhere then you must give a full pathname, e.g.

File myFile = new File ("c:\\cs231\\stuff.dat");

(see discussion below about why 2 slashes are needed.) or a relative pathname with respect to the current working directory:

File myFile = new File ("lab10\\stuff.dat");

File myFile = new File ("..\\stuff.dat");

Some Methods for the File Class:

if (myFile.isFile()) 
   System.out.println(myFile.getName() + " is a file");
else // myFile is directory
{
   System.out.println(myFile.getName() + " is a directory");

   String filenames[] = myFile.list(); // get files in directory

   for (int i=0; i<filenames.length; i++)
      System.out.println(filenames[i]);
}

Escape Sequence

A backslash, \, is called the escape character. It indicates a "special" character is about to be output. When a backslash is encountered in a String, e.g.

System.out.println("Greetings\nfrom Salem.");

the backslash combines with the very next character to form an escape sequence. In the above example, \n represents a newline. The above instruction would output:

Greetings
from Salem

\t (tab) is another such escape sequence.

Using the Backslash to Remove Special Meanings

Some characters in Java have special meanings. For example, single (') and double (") quotes are used to define characters and Strings:

char c = 'a';
String s = "Willamette";

What happens when we want to have a double quote in the String? For example, suppose we want the program to print out

The Title of the book is "Cats and Dogs"

We can't use the instruction

System.out.println("The Title of the book is "Cats and Dogs"");

because Java will get confused. The way around this is to use the escape character which removes the special meaning of symbol that follows it. For example, the following will give us the String we want:

System.out.println("The Title of the book is \"Cats and Dogs\"");

Since the backslash is also a character with special meaning, we need to do a similar thing if we want an actual backslash in our String. Thus, we write

File myFile = new File ("c:\\cs231\\stuff.dat");

where the first slash in the double slash indicates that we are to ignore the special meaning of the following character, namely the second slash. The actual String that is stored in Java is

c:\cs231\stuff.dat


Binary vs ASCII Files

Binary

Suppose we want to store the integer 268.

Recall that in Java, integers are stored in 2's complement using 4 bytes of storage. Thus, 268 has the internal representation:

00000000 00000000 00000001 00001100

Thus, if we want to store 268 in a file it makes sense to store it exactly in the format above using 4 bytes of space. This is called the binary representation. The only downside is that the file is very hard for a normal human to read.

ASCII

The alternative is to store the number 268 in its ASCII representation which would mean saving the ASCII code for the digits "2", "6", and "8". The code is

"2" = 5010 = 001100102

"6" = 5410 = 001101102

"8" = 5610 = 001110002

Thus, 268 would be written to the file as

00110010 00110110 00111000

The advantages of ACII Format

The disadvantages of ASCII Format

Below, we will learn how to read from and write to ASCII files. We will also learn how to store objects using binary format.

What happens if we mistakenly read a binary file as an ascii file?


Files, Streams, Filters


Writing to an ASCII File using PrintWriter

// Create a File
String filename = "DataFiles\\stuff.dat";
File myFile = new File(filename);

// Create an Output Stream
FileOutputStream outStream = new FileOutputStream(myFile);

// Filter bytes to ASCII
PrintWriter out = new PrintWriter(outStream);

// Here we actually write to file
out.println("Hello, this is a test.");
out.println(45);


Reading from an ASCII File using BufferedReader

// Create a File
File myFile = new File("DataFiles\\stuff.dat");

// Create a Character Input Stream
//  Note: FileReader inherits from InputStreamReader
FileReader inStream = new FileReader(myFile)

// Filter the Input Stream - buffers characters for efficiency
BufferedReader in = new BufferedReader(inStream);

// read the first line
String first = in.readLine();

// read the second line
String second = in.readLine();

if (second == null) System.out.println("End of file reached.");


Catching Errors: Exceptions

An exception is a runtime error such as

When an exception occurs in a method we say that the method throws an exception.

For many exceptions (e.g. divide by zero or array index out of bounds) Java "handles" the exception. You don't have to tell Java what to do when the error occurs.

However, for other types of exceptions (e.g. reading and writing to files), Java requires that you explicitly tell it what to do. That is, you must "handle" the exception.

For example, if you look up the readLine method in the BufferedReader class you will see that this method throws an IOException.

There are two ways of doing exception handling:


Propagating the Exception


Catching the Exception

In the above example, we ended up using the default exception handler which did nothing to correct the error. If we want to have more control over what happens we can use a try-catch block which enables us to potentially correct the error or at least alert us to specifically what went wrong:

public String writeToFile(String s, String filename) 
{                  
   try {
      File myFile = new File(filename);       
      FileOutputStream outStream = new FileOutputStream(myFile);
      PrintWriter out = new PrintWriter(outStream); 
      out.println(s);
      out.close();
      return "File " + filename + " successfully written.";
   } catch(Exception e) {
      System.out.println("Error writing to file " + filename + "\n"+e);
      return "Error writing file " + filename ;
   }
}

The code that can throw the exception is placed in the try-block. Should an exception be thrown, the code in the catch-block is executed, otherwise the catch-block is ignored.

Reading and Writing Objects (11.5, 11.6)


We can also save entire objects to a file. These files are stored in binary form. As a result they can't be read in a text editor. To save an object to a file we do the following:

We look at these in more detail below.


Serializable

An ObjectOuputStream will not output an object unless it is a Serializable object. Serializable is known as a tagging interface. Such an interface contains no methods. It instead identifies objects that can be serialized (i.e given serial numbers so they can be identified when saved to disk). For security reasons, objects are not serializable by default.

When saving an object of a class you have created, you must make sure that all instance member variables in that class are also serializable. Many predefined classes (e.g. String, Vector) are already serializable.

For example, recall out Company Database containing an array of Employee objects. For both the Company and Employee classes you must import the java.io package and make the classes serializable:

import java.io.*; 
public class Company implements Serializable
{ 

.... 
}
***********************************
import java.io.*; 
public class Employee implements Serializable
{ 

.... 
}

Now, to write a Company object to a file named filename:

// Writes a Company object to a file
public String write(Company c, String filename) 
{
   try {
      File data = new File(filename);
      ObjectOutputStream out = new ObjectOutputStream(
         new FileOutputStream(data));
      out.writeObject(c);
      out.close();    
      return "Company saved to file " + filename;
   } catch (Exception e) {
      return "Error saving to " + filename + ". Company not saved.\n" + e;
   }          
}

To read a Company object from a file.

// Read Company Object. 
// Assumes Company c is a member variable.

public String read(File data, String filename) {
   String message="";
   try {
      ObjectInputStream in = new ObjectInputStream(
         new FileInputStream(data)); 
      c = (Company) in.readObject();
      in.close();  
      message = "File " + filename + " read.";
   }
   catch (ClassNotFoundException e)
   {
      message = "Class not found. Creating new company.\n" + e;
   }
   catch (IOException e) {
      message = "Error reading file " +  filename + "\n" + e;
   }
   return  message;
}


next lecture