Reading from a file

We have seen that a Scanner can be constructed to read from System.in, and in previous labs we have seen examples in which a Scanner reads its input from a String. We can also construct a Scanner to read from other kinds of input streams, and in particular we can use a Scanner to read from a text file.

With very few changes, we can rewrite the line numberer to read from a file.

package lab6;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class LineNumberer2
{
  public static void main(String[] args) throws FileNotFoundException
  {
    File file = new File("story.txt");
    Scanner scanner = new Scanner(file);
    int lineCount = 1;

    while (scanner.hasNextLine())
    {
      String line = scanner.nextLine();
      System.out.print(lineCount + " ");
      System.out.println(line);
      lineCount += 1;
    }
    scanner.close();
  }
}

Try this code out! To run in Eclipse, the file story.txt must be present in the project directory.

Try changing the filename to something invalid and see what happens. When the file you've named in the Scanner constructor isn't there, the program fails prematurely and something called an exception is generated, in this case a FileNotFoundException. You have seen some kinds of exceptions in previous labs. The FileNotFoundException is a bit different than the exceptions we've seen before, because the compiler requires us to declare in the method heading that this exception might occur:

  public static void main(String[] args) throws FileNotFoundException

The main change is the way that we construct the Scanner. First, we create a File object by giving the constructor the name of the file we want to read. Then we use the File object to construct our Scanner:

    File file = new File("story.txt");
    Scanner scanner = new Scanner(file);
When we construct the Scanner from the given file, the file is opened. This means that the operating system gets involved with finding the actual file on the hard drive and preparing to read its contents. When you're finished reading a file, you should tell the operating system you're done so that it can clean things up (for example, most operating systems record the date and time at which a file was last accessed). This is called closing the file, which we can do with the close method of the scanner:
    scanner.close();

Alternatives for opening a file

In the zyBook you may have seen a slight variation on the strategy above. Instead of creating the Scanner from a File object, you can create the Scanner from an instance of FileInputStream.
    FileInputStream fis = new FileInputStream("story.txt");
    Scanner scanner = new Scanner(fis);
This accomplishes the same thing. The only subtle difference is that if there is an exception, it will occur on creating the FileInputStream instead of on creation of the Scanner.

In the zyBook, they also declare the more general type IOException instead of FileNotFoundException. This makes no practical difference.