11: Files and Streams

What We Will Cover


Continuations

Homework Questions?

Questions from last class?

11.1: Files and File Objects

Objectives

At the end of the lesson the student will be able to:

  • Describe the two common classifications of files
  • Create and use File objects
  • Get information about files from the file system
  • List directory contents

11.1.1: About Program I/O

  • Program I/O = Program Input/Output
    • Input to and output from programs
  • Input can be from a keyboard, mouse or file
  • Output can be to a display screen, printer, or file
  • Note that files can be both input and output devices for programs
  • Advantages of file I/O
    • Data still exists after the program ends
    • Input can be automated (rather than entered manually)
    • Output from one program can be input to another
  • To store and retrieve data in a file, we need two items:
    • A file
    • A file stream object
  • We will look at files first

11.1.2: Files

File: a collection of data stored under a common name on a storage medium.

  • Files provide long-term storage of large amounts of data
  • Usually, you store files on non-volatile storage mediums
    • Magnetic disks
    • Optical disks
    • Flash storage, like USB storage devices
  • File are a single sequence of bytes
  • Byte 0 Byte 1 Byte 2 ... Byte n−1 End-of-file marker

  • The OS keeps track of the number of bytes in a file
    • Using either an end-of-file marker or counting the number of bytes
  • Files must have a name
    • Naming requirements depend on the underlying operating system (OS)
  • The OS organizes files into directories

11.1.3: Types of Files

  • All data and programs are ultimately just zeros and ones
  • Each binary digit can have one of two values: 0 or 1
  • A bit is one binary digit
  • A byte is a group of eight bits
  • Programs group files into two broad categories: text and binary

Text Files

  • In text files, the bits represent printable characters
    • Source code is stored as a text file
  • Files are usually stored as one byte per character (ASCII)
    • Since Java supports Unicode, some characters need two or three bytes
  • Each record (like a line) are often delimited by end-of-line characters
    • Macintosh (before OS-X): "\r"
    • Unix: "\n"
    • Windows: "\r\n"
  • Individual fields within a record are often delimited by commas, tabs or other special characters
  • You can read text files because each byte is translated by display devices into readable characters

Binary Files

  • Everything other than text is called binary
  • Each bit represents some type of encoded information
    • E.g.: program instructions or numeric data
  • Binary files are easily read by the computer but not by humans

For Example

  • If we wanted to store an int value of 1234 in a file
  • We know an int is four bytes long
  • We can store our value as either 1234 or "1234"
  • How we store it determines what is actually written to the file

Description Byte 0 Byte 1 Byte 2 Byte 3
(int) 1234 as binary bits 00000000 00000000 00000100 11010010
(int) 1234 as bytes 0 0 4 210
"1234" as char's '1' '2' '3' '4'
"1234" as ASCII codes 49 50 51 52

11.1.4: Creating File Objects

  • Java uses a File class to perform basic operations on a file or directory
  • You create a File object referring to a file
  • Then you use methods of the File object to query the system for information about the file

Common Constructors for Class File

Class Description
File(String pathname) Creates a File object that refers to the specified pathname.
File(String parent, String child) Creates a File object that refers to the pathname created by combining the parent and child pathnames.
File(File parent, String child) Creates a File object that refers to the pathname created by combining the pathname of parent with the child pathname.

Examples of Creating Files Objects

  • You can create a File object in the current directory
  • File myFile = new File("myfile.txt");
  • Can create a File object using an absolute pathname
  • Specifies the entire path and file name for the file
  • File myFile = new File("C:/docs/myfile.txt");
  • You can use a relative pathname to specify a file
  • Refers to a file starting from the current directory
  • File myFile = new File("docs/myfile.txt");
  • You can use a Universal Naming Convention to refer to a file
  • Starts with two slashes (//) followed by a hostname and pathname
  • File myFile = new File("//server/path/myfile.txt");
  • You can use two strings to specify a file
  • String pathname = "C:/docs";
    String filename = "myfile.txt";
    File myFile = new File(pathname, filename);
    
  • You can use a File object and a string to specify a file
  • File dir = "C:/docs";
    File myFile = new File(dir, "myfile.txt");
    
  • Note that forward slashes work on both UNIX and Windows systems
  • Always use forward slashes to make your code more portable

11.1.5: Methods of the File Class

  • You can use a File object for many tasks
  • The first group of methods test a file or directory
    • For instance: is a file readable or writeable
  • The second group returns information about a file
    • For instance: getting a name or the data last modified
  • The third group works with directories
    • For instance: list directory contents or make directories
  • The fourth group contains some important methods like creating or deleting files

Some Methods that Test a File

Method Description
canRead() Returns true if the pathname exists and can be read by the program.
canWrite() Returns true if the pathname exists and a program can write to it.
exists() Returns true if the pathname exists.
isDirectory() Returns true if the pathname exists and refers to a directory.
isFile() Returns true if the pathname exists and refers to a file.

Some Methods that Return Information about a File

Method Description
getName() Returns the name of the file or directory as a String.
getPath() Returns the path of the file or directory as a String.
lastModified() Returns the time that the file was last modified as the number of milliseconds since January 1, 1970.
length() Returns the length of the file as a long type.

Some Methods that work with Directories

Method Description
list() If the object refers to a directory, returns an array of strings naming the files and directories.
listFiles() If the object refers to a directory, returns an array of File objects for the files and directories.
listRoots() A static method that returns an array of File objects representing the drives available to the current system.
mkdir() Creates the directory named by the File pathname.

Other Methods that work with File Objects

Method Description
createNewFile() Creates a new, empty file if a file with this name does not yet exist.
delete() Deletes the file or directory referred to by the File object.
setReadOnly() Makes the file read-only. If successful, returns true.

11.1.6: Examples Using Files and Directories

  • In this section, we show examples using the File object
  • The first example shows how to get information about a file
  • The second example shows how to work with a directory and list its contents

Getting Information About a File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;

public class FileInfo {
    public static void main(String[] args)
            throws IOException {
        File testFile = new File("testfile.txt");
        testFile.createNewFile();
        if (testFile.exists()) {
            System.out.println("Name:     "
                + testFile.getName());
            System.out.println("Path:     "
                + testFile.getPath());
            System.out.println("Writable: "
                + testFile.canWrite());
        } else
            System.out.println(testFile.getName()
                    + " does not exist.");
    }
}

Listing Directory Contents

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.*;

public class DirList {
    public static void main(String[] args)
            throws IOException {
        File dir = new File("./"); //current directory
        if (dir.exists() && dir.isDirectory()) {
            System.out.println("Dir:     "
                + dir.getCanonicalPath());
            String[] files = dir.list();
            for (int i = 0; i < files.length; i++) {
                System.out.println(files[i]);
            }
        }
    }
}

11.1.7: Summary

  • To identify a file you create a File object
  • You identify the file with either an absolute pathname or a relative pathname
  • To identify a file on a remote computer, you use the Universal Naming Convention
  • The File class provides many methods that you can use to:
    • Check whether a file or directory exists
    • Get information about a file
    • Create or delete files and directories

Check Yourself

  1. What is a file?
  2. What are the two common classifications of files?
  3. What class is used to work with files?

Exercise 11.1

In this exercise, we explore use of a File object.

Specifications

  1. Save the following code file as FileInfo.java.
  2. Add code to the program that displays the following information:
    • Length of the file
    • Time the files was last modified

    Note: to display the timestamp in a more readable format, use the following code:

    import java.util.Date;
    ...
    Date ts = new Date(timestamp);
    System.out.println(ts);
    
  3. Submit your modified FileInfo program as the answer for this exercise.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;

public class FileInfo {
    public static void main(String[] args)
            throws IOException {
        File testFile = new File("testfile.txt");
        testFile.createNewFile();
        if (testFile.exists()) {
            System.out.println("Name:     "
                + testFile.getName());
            System.out.println("Path:     "
                + testFile.getPath());
            System.out.println("Writable: "
                + testFile.canWrite());
        } else
            System.out.println(testFile.getName()
                    + " does not exist.");
    }
}

11.2: Streams and File I/O

Objectives

At the end of the lesson the student will be able to:

  • Describe the purpose of a stream
  • Write text to files
  • Read text from files
  • Describe the procedure for file I/O

11.2.1: Streams

Stream: a one-way transmission path that either delivers data to a destination (screen, file, etc.) or that takes data from a source (keyboard, file, etc.)

  • A stream connects a program to a file
  • Input stream: an object that provides a sequence of bytes to a program
  • Output stream: an object that accepts a sequence of bytes from a program

File Streams

File stream: a one-way transmission path used to connect a program to a file.

  • File streams can be either input or output streams
  • File input streams receive data from a file
  • File output streams send data to a file
  • Each file your program uses will need a separate file stream object

Basic File Streams

  • Since there are two types of files, there are streams to support each type
  • You use character streams to read and write text files
    • FileReader: a stream for reading characters from a file
    • FileWriter: a stream for writing characters to a file
  • You use binary streams to read and write binary files
  • We will use character streams to learn about file I/O because we can see the file contents in a text editor

11.2.2: Layering Streams

  • Usually, any one stream does have not all the functionality you want
  • Instead, it is common to layer two or more streams

For Example

  • To write to a text file, we use a FileWriter object
  • FileWriter fw = new FileWriter("outfile.txt");
    
  • However, a FileWriter does not know how to write different types of data
  • That's why we combine the FileWriter with a PrintWriter
  • PrintWriter out = new PrintWriter(fw);
    
  • Now we can use the overloaded print() and println() methods of a PrintWriter object to write various data types

Buffering

  • Every time a byte or sequence of bytes is written or read to a file, the OS must perform a series of operations
  • Buffering improves performance of I/O by reducing the number of calls to the OS
  • A program copies each output to a block of memory called a buffer
  • The entire buffer is output to disk at once
  • One long disk access takes less time than many smaller ones

Adding a Buffered Layer

  • You use buffered stream classes to improve I/O performance
  • We can add a buffering layer to our previous stream example:
  • File outfile = new File("outfile.txt");
    FileWriter fw = new FileWriter(outfile);
    BufferedWriter buf = new BufferedWriter(fw);
    PrintWriter out = new PrintWriter(buf);
    
  • Another way to write the same functionality:
  • File outfile = new File("outfile.txt");
    PrintWriter out = new PrintWriter(
                      new BufferedWriter(
                      new FileWriter(outfile)));
    
  • Note that the File object is not part of the reformatting
  • You need a reference variable for the File object to access it methods

11.2.3: Example of File I/O

  • As an example, let us write an application that reads and writes files
  • We read a file named infile.txt, which contains the following 3 values:
  • 10
    20
    30
    
  • We sum the numbers and write the sum to a second file named outfile.txt
  • What do you notice that is familiar and what is new about the following code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.*;
import java.util.Scanner;

class Sum3App {
    public static void main(String[] args)
            throws IOException {

        File infile = new File("infile.txt");
        File outfile = new File("outfile.txt");

        // Open the streams
        Scanner in = new Scanner(
                     new BufferedReader(
                     new FileReader(infile)));
        PrintWriter out = new PrintWriter(
                          new BufferedWriter(
                          new FileWriter(outfile)));

        // Read the data
        double num1 = in.nextDouble();
        double num2 = in.nextDouble();
        double num3 = in.nextDouble();

        // Perform the computation
        double total = num1 + num2 + num3;

        // Output the results
        out.println("The sum of the first 3 numbers");
        out.println("in infile.txt is: " + total);

        // Close the streams
        in.close();
        out.close();

        System.out.println("Processing completed");
    }
}
  1. How does the program get its input?
  2. Where does the program send its output?

11.2.4: Procedure for File I/O

  1. Import the Java I/O library and, if you are reading data, the Scanner library.
  2. import java.io.*;
    import java.util.Scanner;
    
  3. Create File objects and open streams as needed for I/O.
  4. File infile = new File("infile.txt");
    Scanner in = new Scanner(
                 new BufferedReader(
                 new FileReader(infile)));
    
    File outfile = new File("outfile.txt");
    PrintWriter out = new PrintWriter(
                      new BufferedWriter(
                      new FileWriter(outfile)));
    
  5. Read data using a Scanner object and write data using print() or println().
  6. // Read the data
    double num1 = in.nextDouble();
    
    // Output data
    out.println("The sum of the first 3 numbers");
    out.println("in infile.txt is: " + total);
    
  7. Close the streams when finished to free up computer resources.
  8. in.close();
    out.close();

11.2.5: Summary

  • Programs can read and write to files using streams
  • A stream is a one-way transmission path that either delivers data to a destination or that takes data from a source.
  • To read and write files, you use character streams
  • Buffers improve the performance of disc operations by reducing the number of device operations
  • To create a stream object with the desired functionality, you layer streams
  • The procedure for File I/O has four steps as shown above.

Check Yourself

  1. What is used to connect a program to a file or File object?
  2. What library is required for file I/O?
  3. How are streams declared?
  4. Why do you layer streams?
  5. What streams do you typically use for reading?
  6. What streams do you typically use for writing?
  7. After opening a stream for reading, how do you read the data?
  8. After opening a stream for writing, how do you write data?
  9. Why should you close a stream after you are done using it in your program?

Exercise 11.2

In this exercise we write a program that copies one line of text from an input stream to an output stream.

Specifications

  1. Save the following code as CopyOneApp.java.
  2. Save the file infile.txt to the same directory as your program source code.
  3. Declare and open an input stream named in that reads from a file named infile.txt.
  4. Declare and open an output stream named out that writes to a file named outfile.txt.
  5. Add code to read the first number from the input stream and save it to the output stream.
  6. Add code to close both of the streams.
  7. Compile and run your program.
  8. View the outfile.txt file using a test editor to verify that one number was copied.
  9. Submit your program as the answer to this exercise.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
import java.util.Scanner;

class CopyOneApp {
    public static void main(String[] args)
            throws IOException {

        File infile = new File("infile.txt");
        File outfile = new File("outfile.txt");

        // Open the streams

        // Read the data

        // Output the results

        // Close the streams

        System.out.println("Processing completed");
    }
}

11.3: More I/O Topics

Objectives

At the end of the lesson the student will be able to:

  • Append data to an existing file
  • Use a loop to read all the data in a file
  • Handle file I/O exceptions

11.3.1: Alternate Syntax for Opening a Stream

  • It is possible to create a stream without using a File object
  • Instead, you can specify the file name as an argument to FileReader or FileWriter
  • For example:
  • Scanner in = new Scanner(
                 new BufferedReader(
                 new FileReader("infile.txt")));
    
    PrintWriter out = new PrintWriter(
                      new BufferedWriter(
                      new FileWriter("outfile.txt")));
    
  • However, when using this technique you can no longer use the methods of the File class

11.3.2: Appending to a File

  • The standard open operation for writing begins with an empty file
  • Even if the file exists you loose all the contents
  • To prevent loosing the information, you must open for appending to the file
  • File outfile = new File("outfile.txt");
    FileWriter fw = new FileWriter(outfile);
    
  • If the file doesn't exist then FileWriter creates it
  • If the file exists then FileWriter positions itself to append to the end
  • The second argument is a boolean value where true means append

For Example

  • The following program will add a message to the file every time we run it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.io.*;
import java.util.Scanner;

class AppendMessageApp {
    public static void main(String[] args)
            throws IOException {
        Scanner input = new Scanner(System.in);

        System.out.print("Enter a message to write: ");
        String message = input.nextLine();

        File outfile = new File("outfile.txt");
        PrintWriter out = new PrintWriter(
                          new BufferedWriter(
                          new FileWriter(outfile, true)));

        out.println(message);
        out.close();

        System.out.println("Finished writing message");
    }
}

11.3.3: Using Loops to Read a File

  • Sometimes you do not know how many lines are in a file
  • To solve this, the typical approach is to use a loop to process the file
  • The Scanner object has methods like hasNext() to see if there is any more input in the stream
  • You can use these methods to test when your program reaches the end of a file

Example Using a Loop to Read a File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;
import java.util.Scanner;

class TextFileReader {
    public static void main(String[] args)
            throws IOException {

        File data = new File("TextFileReader.java");
        Scanner in = new Scanner(
                     new BufferedReader(
                     new FileReader(data)));

        while (in.hasNext()) {
            String line = in.nextLine();
            System.out.println(line);
        }
        in.close();
    }
}

Some Test Methods of a Scanner Object

Method Description
hasNext() Returns true if this scanner has another token in its input.
hasNextLine() Returns true if there is another line in the input of this scanner.
hasNextDouble() Returns true if the next token can be interpreted as a double value.
hasNextInt() Returns true if the next token can be interpreted as an int value.

11.3.4: Handling I/O Exceptions

  • File I/O requires you to work with I/O exceptions
  • To handle I/O exceptions, you need to throw them or code try-catch statements
  • So far, we have been throwing the exceptions
  • Instead of throwing the exceptions, we can handle them in the usual way
  • try {
      // One or more statements at least one of which
      //   should be capable of throwing an exception
    } catch (Exception e) {
      // Exception handling code
      // Can have many catch blocks
    }
    
  • Shown below are two common exception classes you can work with
  • Note that since we use a Scanner for input, we can get other exceptions as well
  • The Scanner exceptions were covered in lesson 9.3: Exception Handling Basics

Two Common I/O Exceptions

Exception Description
IOException General purpose I/O exception.
FileNotFoundException Thrown when a program tries to open a file that does not exist.

Example Handling File Exceptions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.*;
import java.util.Scanner;

class TextFileReader2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("File name to read: ");
        String fileName = input.nextLine();
        showFile(fileName);
    }

    public static void showFile(String fileName) {
        Scanner in = null;
        try {
            File data = new File(fileName);
            in = new Scanner(
                 new BufferedReader(
                 new FileReader(data)));
            while (in.hasNext()) {
                String line = in.nextLine();
                System.out.println(line);
            }
            in.close();
        } catch(FileNotFoundException fnfe) {
            System.out.println("No such file");
            return;
        } catch(IOException ioe) {
            System.out.println("Got an IOException.");
            in.close();
            ioe.printStackTrace();
            System.exit(1);
        }
    }
}

11.3.5: Avoiding a FileNotFoundException

  • We can use a File object to avoid a FileNotFoundException
  • Avoiding exceptions is often preferable where easily done
  • You should reserve exception handling for true errors
  • Note that even if you avoid a FileNotFoundException, you still need to handle the general IOException
  • An IOException is a catch-all for file I/O exceptions
  • By avoiding or handling normal exceptions, we make sure that any IOException that does occur is truly an exceptional problem
  • The following shows how to use a File object to avoid a FileNotFoundException

Example Avoiding a FileNotFoundException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.io.*;
import java.util.Scanner;

class TextFileReader3 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("File name to read: ");
        String fileName = input.nextLine();
        showFile(fileName);
    }

    public static void showFile(String fileName) {
        Scanner in = null;
        try {
            File data = new File(fileName);
            if (data.exists()) { // avoid FileNotFoundException
                in = new Scanner(
                     new BufferedReader(
                     new FileReader(data)));
                while (in.hasNext()) {
                    String line = in.nextLine();
                    System.out.println(line);
                }
                in.close();
            }
        } catch (IOException ioe) {
            System.out.println("Got an IOException.");
            in.close();
            ioe.printStackTrace();
            System.exit(1);
        }
    }
}

11.3.6: Summary

  • The standard open operation for writing begins with an empty file
  • Even if the file exists you loose all the contents
  • To prevent loosing the information, you must open for appending to the file new
  • File outfile = new File("outfile.txt");
    FileWriter fw = new FileWriter(outfile);
    
  • Sometimes you do not know how many lines are in a file
  • To solve this, the typical approach is to use a loop to process the file
  • The Scanner object has methods like hasNextLine() to see if there is any more input of the correct type in the stream
  • You can use these methods to signal when your program reaches the end of a file
  • while (in.hasNextLine()) {
        String line = in.nextLine();
        System.out.println(line);
    }
    
  • Many Java I/O classes throw I/O exceptions that you need to handle
  • You must either throw the exceptions or code try-catch statements
  • Some exceptions can be avoided, which is often preferable
  • Exceptions should be reserved for exceptional conditions and not the normal flow of your program

Check Yourself

  1. How do you keep a file that is opened for writing from destroying existing information?
  2. What looping structure do you use to read all the data in a file?
  3. What two exceptions do you often need to handle for file I/O?
  4. How do you avoid throwing a FileNotFoundException

Exercise 11.3

In this exercise we explore reading all the lines of a file using a loop and handling I/O exceptions.

Specifications

  1. Save the following code file as ShowFileApp.java.
  2. Using the fileName entered by the user, add code that displays the file to the screen.
  3. Submit your completed program as the solution for this exercise.
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.*;
import java.util.Scanner;

public class ShowFileApp {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("File name to read: ");
        String fileName = input.nextLine();

        // Add code to read and display a file here
    }
}

Wrap Up

Home | WebCT | Announcements | Schedule | Expectations | Course info
Help | FAQ's | HowTo's | Links

Last Updated: November 06 2005 @22:30:09