Reading Data from a File

Site: Saylor Academy
Course: CS101: Introduction to Computer Science I
Book: Reading Data from a File
Printed by: Guest user
Date: Monday, October 21, 2024, 9:47 PM

Description

This chapter discusses Java's FileReader and BufferedReader classes in detail. FileReader and BufferedReader classes are used together when reading data from an external file. The use of the BufferedReader class allows data to be buffered as it is read from a file before manipulating it. The readLine() method of the BufferedReader class reads a line of text from a character-oriented input stream, and puts it into a new String object.

1. Reading from Text Files

An input stream can be connected to a text file. With character-oriented input streams, characters are automatically translated from the external (disk file) format to the internal (Java char) format.

Chapter Topics:
  • Reader
  • FileReader and BufferedReader
  • readLine()
  • Text file copy program
  • C-style input loop


Question 1:

What is the ancestor class of all character-oriented input streams?

Source: Bradley Kjell, http://programmedlessons.org/java5/Notes/chap84/ch84_1.html
Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 License.

2. Reader Streams


Answer:

Reader

Reader Streams

readerHierarchy (1)

The diagram shows some of the classes in the Reader hierarchy. Look at your Java documentation for details of these and other classes. You should not expect to remember everything in the java.io package, but you should be familiar enough so that you can look in the documentation for what you need.

The Reader hierarchy looks much like the Writer hierarchy.


Question 2:

(Thought question: ) What two classes are used together for efficient input of characters from a file?

  

3. FileReader and BufferedReader


Answer:

FileReader and BufferedReader

FileReader and BufferedReader

charInputStream

FileReader is used for input of character data from a disk file. The input file can be an ordinary ASCII, one byte per character text file. A Reader stream automatically translates the characters from the disk file format into the internal char format.

The characters in the input file might be from other alphabets supported by the UTF format, in which case there will be up to four bytes per character. In this case, also, characters from the file are translated into char format.

As with output, it is good practice to use a buffer to improve efficiency. Use BufferedReader for this.


Question 3:

What method reads a line of characters from a BufferedReader?

4. Example Program


Answer:

The readLine() method.

Example Program


import java.io.*;
class ReadTextFile
{
 public static void main ( String[] args ) 
 {
   String fileName = "reaper.txt" ;
   String line;

   try
   {      
     BufferedReader in = new BufferedReader( new FileReader( fileName  ) );
     
     line = in.readLine();
     while ( line != null )  // while not end of file
     {
       System.out.println( line );
       line = in.readLine();
     }
     in.close();
   }
   catch ( IOException iox )
   {
     System.out.println("Problem reading " + fileName );
   }
 }
}

The readLine() method reads a line of text from a character-oriented input stream, and puts it into a new String object which it returns as a reference. If there is no more data in the file, it returns null.

When a file is opened it is prepared for use. This program opens a file for reading. (The analogy is to opening a paper file in an office.)

The file reaper.txt is opened for reading when the FileReader stream is constructed. If the file does not exist in the current directory, an IOException is thrown.

Next, the program reads each line of the file and writes it to the monitor. When end-of-file is detected the program quits.

This is an extremely common programming pattern: reading and processing data while not end-of-file. Usually in documentation, end-of-file is abbreviated EOF.

It would be worthwhile to play with this program. Create reaper.txt with a text editor if it does not already exist.

Question 4:

Does this program create a new String object for each line of text in the file?

5. Constructors


Answer:

Yes. All this object creation (and the garbage collector running in the background) takes processor time, but for most programs this is not noticeable.

Constructors


The constructor for BufferedReader looks like this:

BufferedReader( Reader in ) 

The constructor for FileReader looks like this:

FileReader( String fileName ) throws FileNotFoundException

The methods from BufferedReader which interest us are:

void close() throws IOException       // close the stream

int read() throws IOException // read a single character into an int

String readLine() throws IOException // read one line of characters into a String.

The read() method will be discussed later. (Both classes have other constructors and other methods which will not be discussed here).

Question 5:

What does the close() method do with an input stream?

6. Closing Input Files


Answer:

It says that the program no longer needs the file. The system then finishes any operations in progress on the file.

Closing Input Files

Closing an input file is less important than closing an output file. When end-of-file is detected there is no more data. (There is no need to flush an input file). But close input files anyway. Doing so lets the operating system manage resources more effectively.

Of course, to write to a file after reading it in, the file must first be closed and then opened for output (with a FileWriter stream). A word processor program might do this, for example.

Also, a program can open a file so that it can be both read and written during the same session. A file opened this way is said to be open for direct access or random access. This subject is not covered in these notes.

Question 6:

Can a program simultaneously read from one file and write to another?

7. Text File Copy Program


Answer:

Yes.

Text File Copy Program

copyImage

The next example program copies a source text file to a destination text file. An already existing file with the same name as the destination file will be destroyed. The names of the source and destination come from the command line. It looks like this:

java CopyMaker original to copy

The illustration shows this working in a command prompt window. Notice how the original file and the copy have the same number of bytes.

Most operating systems come with a user interface that includes a file copy command. The order of the source file and the destination file differs between operating systems. Getting them backwards might be disastrous! Our program requires the word "to" in the command line to ensure that the user knows the correct order.

The program will use a FileReader and a BufferedReader for input and a FileWriter and a BufferedWriter for output.

Question 7:

Can this copy program be used to copy a Microsoft Word document? 

8. Flow Chart of the Program


Answer:

No. Most word processing files use their own format, which is not understood by a Reader that is expecting UTF
characters. To process a Word file, you would use byte-oriented streams, InputStream and OutputStream.

Flow Chart of the Program

copyFlowChart

The general design of the program is given in the flowchart. Of course, many details are left out. The purpose of the chart is to show the overall logic.

The box "Read a line of source" appears in two places—before the loop gets started and in the body of the loop. Study the logic to see that this is correct.

Question 8:

Will this logic correctly copy an empty file (a file that exists, but returns end-of-file immediately)?

9. Skeleton Program


Answer:

Yes.

Skeleton Program

class CopyMaker
{
  String sourceName, destName;
  BufferedReader source;
  PrintWriter dest;
  String line;

  CopyMaker ( String source, String dest )
  {
    sourceName = source;
    destName   = dest;
  }
  
  private boolean openFiles()  // return true if files open, else false
  {
  }

  private void copyFiles()
  {
  }

  private void closeFiles() 
  {
  }

  public static void main ( String[] args ) 
  {
    if ( args.length == 3 && args[1].toUpperCase().equals("TO") )
    {
      CopyMaker cp = new CopyMaker( args[0], args[2] );
      if ( cp.openFiles() )
      {
        cp.copyFiles() ; 
        cp.closeFiles() ;
       }
    }
    else
      System.out.println("java CopyTextFile source to destination");
  }

}

The program must work correctly with an empty file. This may seem dumb, but there is no reason to have a program break when it is used in an unexpected fashion. Here is the copy program with pieces left out:

Rather than write one big main() it is convenient to define an object whose several methods implement the steps in copying files. Potentially the object could be used as a component of a larger program.

The main() method collects information from the user. If the information looks correct, it creates a CopyMaker object and calls its methods.


Question 9:

If the files open successfully but there is a problem in making the copy, should the program close the files?

10. Opening Files


Answer:

Yes.

Opening Files

Look at the openFiles() method. It opens a BufferedReader stream with the source file and a PrintWriter with the destination file. Decide what should go in each box, and click it to verify your choice.

class CopyMaker
{
  String sourceName, destName;
  BufferedReader source;
  PrintWriter dest;
  String line;

   // return true if both files open, otherwise return false
   //
   private boolean openFiles()  
   {
     // open the source
     try
     {      
       source = new (new FileReader( sourceName ));
     }
     catch (  iox )
     {
       System.out.println("Problem opening " + sourceName );
       return false;
     }

     // open the destination
     try
     {      
       dest = new PrintWriter( 
           new (new FileWriter( destName )) );
     }
     catch (  iox )
     {
       System.out.println("Problem opening " + destName );
       return false;
     }

     return   ;
   }

    . . . . .  the rest of the program . . . . .
   
}


Question 10:

Click in the blanks.

11. Closing Files


Answer:

Click!

Closing Files

Here is the file closing method. It is possible (though rare) for closing a file to fail. The close() method of PrintWriter does not throw an exception

class CopyMaker
{
   String sourceName, destName;
   BufferedReader source;
   PrintWriter dest;
   String line;

   private void closeFiles() 
   {
     // close the source
     try
     {      
       source.();
     }
     catch ( IOException iox )
     {
       System.out.println("Problem closing " +);
     }

     // close the destination
     dest.();
   }

    . . . . .  the rest of the program . . . . .
   
}


Question 11:

Since errors on closing a file are rare, would it be OK to have closeFiles() throw its IOExceptions?

12. CopyFile Method


Answer:

Probably this would be OK.

CopyFile Method

The copyFiles() method finally gets down to copying the file. The loop that does the work is just a few statements long!

class CopyMaker
{
   String sourceName, destName;
   BufferedReader source;
   BufferedWriter dest;
   String line;

   private void copyFiles()
   {
     try
     {      
       line = source. ;
       
       // while not End-of-File
       while (  )
       {
         dest. (line);
         line = source. ;
       }
     }
     catch ( IOException iox )
     {
       System.out.println("Problem reading or writing" );
     }
   }
}

Question 12:

Click in the blanks.

13. Complete Program


Answer:

click.. click.. click.. click.. click

Complete Program

Here is the complete program, suitable for copying to an editor, saving to a file, and running.

              
import java.io.*;

class CopyMaker
{
  String sourceName, destName;
  BufferedReader source;
  PrintWriter dest;
  String line;

  CopyMaker ( String source, String dest )
  {
    sourceName = source;
    destName   = dest;
  }

  private boolean openFiles()  // return true if files open, else false
  {
    // open the source
    try
    {      
      source = new BufferedReader(new FileReader( sourceName ));
    }
    catch ( IOException iox )
    {
      System.out.println("Problem opening " + sourceName );
      return false;
    }
    // open the destination
    try
    {      
      dest = new PrintWriter( new BufferedWriter(new FileWriter( destName )) );
    }
    catch ( IOException iox )
    {
      System.out.println("Problem opening " + destName );
      return false;
    }
    return true;
  }

  private void copyFiles()   
  {
    try
    {      
      line = source.readLine();
      while ( line != null )
      {
        dest.println(line);
        line = source.readLine();
      }
    }
    catch ( IOException iox )
    {
      System.out.println("Problem reading or writing" );
    }
  }

  private void closeFiles()   
  {
    // close the source
    try
    {      
      source.close();
    }
    catch ( IOException iox )
    {
      System.out.println("Problem closing " + sourceName );
    }
    // close the destination
    dest.close();
  }

  public static void main ( String[] args ) 
  {
    if ( args.length == 3 && args[1].toUpperCase().equals("TO") )
    {
      CopyMaker cp = new CopyMaker( args[0], args[2] );
      if ( cp.openFiles() )
      {
        cp.copyFiles() ; 
        cp.closeFiles() ;
       }
    }
    else
      System.out.println("java CopyTextFile source to destination");
  }

}

Question 13:

Does this program make an exact copy of the input file? Hint: what if the original file was made on a Unix computer and that the copy program was running on a Windows computer?

14. C-style Input Loop


Answer:

No. The line terminating characters may be different in the copy. Sometimes this is a useful feature if you often copy text files between different types of computer.

C-style Input Loop

Here is the loop from the copyFile() method.

 line = source.readLine();
  while ( line != null )
  {
   dest.write(line);
   dest.newLine();
   line = source.readLine();
  }


Here is the same loop written in a style that is commonly used with the C programming language. This style also works for Java:

  while ( (line = source.readLine()) != null )
  {
   dest.write(line);
   dest.newLine();
  }


The key to understanding this is to understand that an assignment statement is an expression and has a value. That value is the value that is assigned to the variable. So this:

(line = source.readLine())


has a value that is non-null after a successful readLine() and null upon end-of-file. Say that the file has data in it:

cStyleLoop

This may be more bother than it is worth, but programmers familiar with C are likely to use this style, so you will see it often.


Question 14:

Will this form of the loop work correctly with an empty file?

15. End of Chapter


Answer:

Yes.

End of Chapter

You have reached the end this chapter. You may wish to review the following. Click on a subject that interests you to go to where it was discussed.