Parsing lines of a file

Text files are usually organized into lines, and so a loop for processing a text file usually has the following form:
open the file
while there are more lines
    get the next line
    process the line
close the file
The step where it says "process the line" can be quite involved, however. For example, suppose a file contains lines such as
Firstname Lastname 8 10 7 7 4
where the numbers are lab scores, and the desired output for each line is to print the name followed by the sum of the scores divided by a fixed possible total. If the total possible in this case is 50, we'd get output of the form
Firstname Lastname 7.2
for this line. The pseudocode for "process the line" might look like this:
read the first name
read the last name
while there are more numbers
    add the numbers to the total
print name and average
Each line is just a string that you can read with a temporary Scanner. This is simplest if you first write a helper method whose job is to process just one line and print the name and average:

  private static void printOneAverage(String line, int pointsPossible)
  {   
    // construct a temporary scanner, just to read data from this line
    Scanner temp = new Scanner(line);
    
    // get the first and last name
    String first = temp.next();
    String last = temp.next();
    
    // add up all the scores
    double total = 0.0;
    while (temp.hasNextInt())
    {
      int value = temp.nextInt();
      total += value;
    }
    
    // print the average
    double average = total / pointsPossible;
    System.out.println(first + " " + last + " " + average);
  }

Then the original pseudocode is captured in a method that opens and reads the file, calling printOneAverage for each line:
  private static void printAllAverages(String filename, int pointsPossible) 
      throws FileNotFoundException
  {
    // open the file
    File file = new File(filename);    
    Scanner scanner = new Scanner(file);
    
    // while there are more lines...
    while (scanner.hasNextLine())
    {
      // get the next line
      String line = scanner.nextLine();
      
      // process the line
      printOneAverage(line, pointsPossible);
    }
    
    // close the file
    scanner.close();

  }
Then the code for the main method is simple:
public class QuizAverager
{
  public static void main(String[] args) throws FileNotFoundException
  {
    // read from a file called "scores.txt", assume total possible points is 50
    printAllAverages("scores.txt", 50);
  }
  
Try this on the sample text file scores.txt. You can find the complete QuizAverager.java source code here.

Advice: When you read a file, decide whether you want to read it item-by-item, or line-by-line. Use hasNextLine() with nextLine(); use hasNext() with next(). Don't mix them up.

Checkpoint 1

  1. Modify the code for LineNumberer so that the input file comes from a different project, using a relative path to identify it. For example, run LineNumberer on the source file SimpleLoops.java that was part of lab 5.
  2. Write a method that reads a text file and, for each line, prints out the number of words in the line. Try it on the file story.txt.