CSC 012

Introduction to Computer Science

Summary of 12/13 Lecture

File I/O.  (10.3, 10.4).

Output Files

The last time we met, we described the process of converting input files from streams of bytes to appropriate data types.  Tonight we'll see how to reverse the process and send output to a file, rather than to the screen.

  1. PrintWriter object (converts a String to a stream of chars)

  2. BufferedWriter object (offers staging area for char stream)

  3. FileWriter object (converts char stream to byte stream)

  4. file receives byte stream from FileWriter object

The corresponding steps in your Java program (in reverse order) are:

  1. String fileName associated with text file.

  2. FileWriter fr = new FileWriter (fileName);

  3. BufferedWriter buffer = new BufferedWriter (fr);

  4. PrintWriter out = new PrintWriter (buffer);

  5. out.println (data);

  6. out.close();

Our first example mimicks the familiar "Hello World" program, sending output to a file rather than to the screen.

//File:    Hello0.java
import java.io.*;
import iostuff.*;

class Hello0
{
       public static void main (String [] args)
        {
            System.out.print ("What's the name of your file? ");
            String fileName = Keyboard.readString();
       
            //FileWriters convert char streams to byte streams
            FileWriter fr = new FileWriter (fileName);
       
            //PrintWriters convert Strings to char streams                
            PrintWriter out = new PrintWriter (fr);
       
            out.println ("Hi there gang!!. Ain't this great?");
            out.close();
        }
}

An attempt at compiling this program generates the following error message:

>javac Hello0.java
Hello0.java:12: Exception java.io.IOException must be caught, or it must be declared in the throws clause of this method.
FileWriter fr = new FileWriter (fileName);
^
1 error

As we discussed last time, the creation of I/O objects can generate I/O exceptions.  Java requires that we check for these exceptions.  So the following modified version works just fine:

//File:    Hello.java
import java.io.*;
import iostuff.*;

class Hello
{
       public static void main (String [] args)
        {
            System.out.print ("What's the name of your file? ");
            String fileName = Keyboard.readString();
       
           try
            {
                //FileWriters convert char streams to byte streams
                FileWriter fr = new FileWriter (fileName);
           
                //PrintWriters convert Strings to char streams                
                PrintWriter out = new PrintWriter (fr);
           
                out.println ("Hi there gang!!. Ain't this great?");
                out.close();    //NOTE:  Important to close output files after completing output.
                                 //              Otherwise you can lose some or all of your data

            }
           catch (IOException e)
            {
            }
    }
}

>javac Hello.java

>java Hello
What's the name of your file?
hello.txt

>type hello.txt
Hi there gang!!. Ain't this great?

This is probably a good time to mention an alternative to the try-catch clause.  Checking for exceptions is much like a game of hot potato.  If you don't provide for the I/O exceptions, then you can throw it to the calling program.  The following is an acceptable rewrite of the previous Hello program.

//File:    Hello2.java
import java.io.*;
import iostuff.*;

class Hello2
{
    public static void main (String [] args) throws IOException
    {
        System.out.print ("What's the name of your file? ");
        String fileName = Keyboard.readString();
       
        //FileWriters convert char streams to byte streams
        FileWriter fr = new FileWriter (fileName);
       
        //PrintWriters convert Strings to char streams
        PrintWriter out = new PrintWriter (fr);
       
        out.println ("Hi there gang!!. Ain't this great?");
        out.close();
    }
}

Finally, output to a file can be buffered.  That is, rather than sending data items one by one to the file (which is time consuming), we can collect data in RAM ( in an area called a buffer) and occasionally send data to the file.  This is accomplished through the BufferedWriter class as follows:

//File:    BufferedHello.java
import java.io.*;
import iostuff.*;

class BufferedHello
{
    public static void main (String [] args) throws IOException
    {
        System.out.print ("What's the name of your file? ");
        String fileName = Keyboard.readString();
       
        //FileWriters convert char streams to byte streams
        FileWriter fr = new FileWriter (fileName);
       
        BufferedWriter buffer = new BufferedWriter (fr);
       
        //PrintWriters convert Strings to char streams
        PrintWriter out = new PrintWriter (buffer);
       
        out.println ("Hi there gang!!. Ain't this great?");
        out.close();
    }
}

Command Line Arguments

In solving one of the lab problems last time, we made use of command line arguments, answering the implicit question:

In the line    public static void main (String [] args)    whats the String [] args for?

The answer is that the parameter "String [] args" provides a way to communicate information to the program from the command line.  Let's look at the following example:

//File:    TestArgs.java
import iostuff.*;
public class TestArgs
{   
       public static void main (String [] args)
        {
            System.out.println ("args [0] = " + args [0]);
            System.out.println ("args [1] = " + args [1]);
            System.out.println ("args [2] = " + args [2]);
        }
}

>java TestArgs How are you?
args [0] = How
args [1] = are
args [2] = you?

Clearly, String [] args represents an array of Strings. By adding a sequence of Strings to the command line, as we just did, the array is filled with those Strings.  In fact, this provides an effective way for the user to inform the program about files.

//File:    HelloArgs.java
import java.io.*;
import iostuff.*;

class HelloArgs
{
    public static void main (String [] args) throws IOException
    {
//            Don't need to ask the user for file name.   
//            System.out.print ("What's the name of your file? ");
//            String fileName = Keyboard.readString();
       
            //FileWriters convert char streams to byte streams
            FileWriter fr = new FileWriter (args[0]);
           //Pass the filename through the command line argument

            //PrintWriters convert Strings to char streams
            PrintWriter out = new PrintWriter (fr);
       
            out.println ("Hi there gang!!. Ain't this great?");
            out.close();
    }
}

>java HelloArgs output.txt

>type output.txt
Hi there gang!!. Ain't this great?

File Output of Tables

It's one thing to output a String to a file, but how about something a bit more complicated.  The following code has been added to our IntFiles class:

    //The following function outputs a list of n ints, one number per line,
    //to fileName

    public static void writeOut (String fileName, int [] list, int n)
    {
           try
            {
                FileWriter fr = new FileWriter (fileName);
                BufferedWriter buffer = new BufferedWriter (fr);
                PrintWriter out = new PrintWriter (buffer);

               for (int row=0; row<n; row++)
                {
                    out.println (list[row]);
                }
           
                out.close();
            }
           catch (IOException e)
            {
            }
    }

Finally, the following function outputs a table of ints.

    //The following function outputs a table of ints containing r rows and c columns
    //to fileName

    public static void writeOutTable (String fileName, int [] [] list, int r, int c)
    {
           try
            {
                FileWriter fr = new FileWriter (fileName);
                BufferedWriter buffer = new BufferedWriter (fr);
                PrintWriter out = new PrintWriter (buffer);

                for (int row=0; row<r; row++)
                {
                   for (int col=0; col<c; col++)
                    {
                        out.print (list [row] [col] + "\t");
                    }
                    out.println();
                }
           
                out.close();
            }
           catch (IOException e)
            {
            }
    }

Finally, we examine a possible solution to the Exercise from last time.

At Home Exercise.  Expand the above readInTable() method to allow for a variable number of columns.  I think this would require the following signature:

public static int [] readInTable (String fileName, int [] [] list)

Note that the return type of the function is now int[] rather than simply int.  That's because we would like the function to tell us the number of columns as well as the number of rows.  So, the concluding statements in our modified method might be:

int [] temp = new int [2];
temp [0] = row;
temp [1] = col;

return temp;

In fact, the following represents a solution (added to IntFiles.java):

    //The following function inputs a table of ints from fileName
    //and returns the number of rows and columns
    public static int [] readTable (String fileName, int [] [] list)
    {
           int row=0;
           int col=0;
            String s;
           try
            {
                //The FileReader converts byte stream to char stream
                FileReader fr = new FileReader (fileName);

                //The BufferedReader enables efficient buffering of stream
                BufferedReader inFile = new BufferedReader (fr);

                String line = inFile.readLine(); //readLine() is in BufferedReader class
           
               while (line != null)
                {
                    StringTokenizer tokenizer = new StringTokenizer (line);
                   int ncols = tokenizer.countTokens();
                    //countTokens() is member function in StringTokenizer class.  It's perfect for this application.

                   for (col=0; col<ncols; col++)    //Don't need to specify 3 here
                    {
                        s=tokenizer.nextToken();
                        list [row] [col] = Integer.parseInt (s);
                    }
                    row++;
                    line = inFile.readLine();
                }
           
                inFile.close(); //not invoked if throws exception
               
            }
           catch (FileNotFoundException e)
            {
                System.out.println ("The file " + fileName + " was not found.");
            }
           catch (IOException e)
            {
                System.out.println (e);
            }
       
            int [] temp = new int [2];
            temp[0]=row;
            temp[1]=col;
       
            return temp;

        }

Putting it all together, a driver for this function might look as follows:

//File:    TestTableArgs.java
import iostuff.*;
public class TestTableArgs
{   
    public static void main (String [] args)
    {
           int [] [] table = new int [8][5];

            String infile = args[0];
            int [] results = IntFiles.readTable (infile, table);
       
           int rows = results [0];
            int cols = results [1];
       
            String outfile = args[1];
            IntFiles.writeOutTable (outfile, table, rows, cols);
        }
}

Back to CSC 012 Home Page