Reading a file in Java

There are many ways to read a file in Java. This is a pattern that you may find useful. It is line oriented, meaning that it processes one line at a time. The basic idea is to split the processing into two parts:
  1. getting the lines, one at a time
  2. processing each line in turn

Getting the lines of a file

The java class Scanner. provides convenient mechanisms for performing these tasks. Let us first consider the first of the two tasks. The following code does this by:

  1. constructing a File object given a fileName
  2. constructing a Scanner using the File object
  3. looping until there are no more lines
  4. getting a line
  5. processing it


    Scanner fileScanner = new Scanner(new File(fileName));

    while (fileScanner.hasNextLine()) {
      String line = fileScanner.nextLine();

      // now do something with line
    }
    
    fileScanner.close();

By delegating the responsibility of getting lines to the Scanner, the programmer need to worry that different operating systems have different conventions for delimiting the end of a line.

One thing this code ignores is that this constructor of a Scanner may throw a FileNotFoundException. Thus, the code needs to be enclosed in a try/catch or the method in which this code exists must declare that it throws a FileNotFoundException.

Processing the lines of a file

The Scanner class is also useful in processing the lines. Simply construct a Scanner using the line and extract information from it. When this is done, the code becomes:


    Scanner fileScanner = new Scanner(new File(fileName));

    while (fileScanner.hasNextLine()) {
      String  line        = fileScanner.nextLine();
      Scanner lineScanner = new Scanner(line);
              lineScanner.useDelimiter(fieldDelimiter);

      // now extract information from the lineScanner
    }
    
    fileScanner.close();

Generalizing further

So far we have used two levels of Scanner to process our file. There is no reason that we can not go even further. For example, we might think of the line as containing multiple sections, with each section containing multiple values. As long as one uses different delimiters, we can continue the process and continue to any number of levels. Here is the code for lines with sections and values within section.


    Scanner fileScanner = new Scanner(new File(fileName));

    while (fileScanner.hasNextLine()) {
      String  line        = fileScanner.nextLine();
      Scanner lineScanner = new Scanner(line);
              lineScanner.useDelimiter(sectionDelimiter);

      while (lineScanner.hasNext()) { // can we always loop ?
        String  section = lineScanner.next();
        Scanner sectionScanner = new Scanner(section);
        sectionScanner.useDelimiter(valueDelimiter);

        // now extract information from the sectionScanner
      }
    }
    
    fileScanner.close();

A variation on the above is to split the line into sections using the String.split(sectionDelimiter) method. The sections can then be processed as required, perhaps using a Scanner. When there are multiple sections, it is useful to write a method for each section. This separates the logic of processing a section into a method rather than mixing it in with the loop that reads lines and sections. This often simplifies the logic and reduces bugs.

Now you try it

Assume that you have a line oriented file. Each line contains four sections delimited by the character |. The four sections are:
  1. the students name
  2. a number of quiz grades, delimited by the character ;
  3. a number of homework grades, delimited by the character ;
  4. an exam grade

A sample line looks like:

   Jo Jackson|10;8;7;2;0|78;55;92;41|98

Your task is to use the patterns shown above to extract all the data from a file containing lines like the sample.

Fritz Sieker - Nov 2011