Skip to content

Lab 6: File I/O

In this lab, you will implement a class that reads text from a file and instantiates objects based on its contents.

Learning Objectives

After completing this lab, you should be able to:

  • Use Scanner to read tokens from a file
  • Handle exceptions from file I/O operations using try and catch
  • Use ArrayList to store a dynamic number of objects
  • Iterate over an ArrayList to search for a specific object

AI Assistance ✨

As usual, do not use AI tools to generate code solutions. However, you are encouraged to use them as a reference for syntax and method usage. But remember, you won't be able to use AI tools during exams, so make sure you understand the concepts and remember the key syntax!

We recommend using Microsoft Copilot Chat (free for all JMU students). You are free to use other AI tools if you prefer.

Getting Started

First, download the following files and put them in your cs159 folder, under src/labs/lab06 (you will need to create a lab06 folder):

Part 1: Parsing the File

Open up your cs159 folder in VS Code, then navigate to and open the CourseCatalog.java file for editing.

Your task is to implement the loadFromFile method in the CourseCatalog class. This method should read course data from a file and create Course objects based on that data.

The file format is as follows:

<subject> <number> <credits> <course name>

For example:

CS 159 3 Advanced Programming
MATH 235 4 Calculus I

Note that the subject, number, and credits are separated by spaces, and the course name may contain spaces.

Scanner and File I/O

To read from a file, you will use the Scanner class along with the File class. Scanner works just like it does with System.in, but instead of reading from the console, it reads from a file.

  1. Start by importing the necessary classes near the top of your CourseCatalog.java file, after the package declaration:

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Scanner;
    
  2. Next, in your loadFromFile method, you will create a Scanner object that reads from the specified file. You will also need to handle the potential FileNotFoundException that can be thrown if the file does not exist.

    • Write the following two lines inside your loadFromFile method:

          File file = new File(filename);
          Scanner input = new Scanner(file);
      
  3. There should now be a red squiggly line under new Scanner(file). This is because the Scanner constructor can throw a FileNotFoundException, which is a checked exception. You need to handle this exception using a try-catch block.

    • Put the two lines inside a try block, and add a catch block to handle the exception:

          try {
              File file = new File(filename);
              Scanner input = new Scanner(file);
          } catch (FileNotFoundException e) {
              System.out.println("File not found: " + filename);
              return;
          }
      
    • What this means is that if the file is not found, the program will print an error message and exit the method early.

Reading the File

Now that you have a Scanner object that reads from the file, you can use it to read each line of the file, parse the course data, and create a new Course object to add to the list. So, if the file has 3 lines, you will need to create 3 Course objects and add them to the courses list.

  1. You will want a while loop that continues as long as there are more lines to read.

    • Recall that Scanner has a method called hasNextLine() that returns true if there is another line to read.
  2. Inside the loop, you have two choices on how to parse each line:

    • Use Scanner methods to read each piece individually in this method.
      • Read the subject, course number, and credits first.
      • Then, read the rest of the line (nextLine()) as the course name.
    • Better: Use nextLine() to read the entire line as a string, then parse the string using another Scanner or string methods.
      • Best: Organize your code by creating a private helper method called parseLine(String line) that takes a line of text and returns a Course object.
      • Using a second Scanner object to parse the line may be easier than using string methods.
  3. Regardless of approach, for each line, you will need to:

    1. Read the course subject (String).
    2. Read the course number (int).
    3. Read the course credits (int).
    4. Read the course name (String, may contain spaces).
      • Remember that nextLine() returns the rest of a line, including spaces.
      • This may result in a leading space, which you can remove with trim().
    5. Create a new Course object using the data read above.
    6. Add the Course object to the courses ArrayList.

    AI: Quick Reference ✨

    You can ask AI tools for quick reminders of Java syntax or methods. For example, you might ask:

    • "What is a private helper method in Java?"
    • "How can I use a Scanner to parse a String in Java?"
    • "How can I split a String by spaces in Java?"

    Use these tools to help you remember syntax and methods, but do not ask them to write the full code for you. You might consider generating a reference sheet:

    • "Create a table of common Scanner methods in Java."

    Remember, AI responses may not always be correct. Online references may be more helpful, such as w3schools Java Scanner Methods.

  4. Make sure to close the Scanner object at the end of the try block:

        input.close();
    
    • Why? It is good practice to close resources when you are done with them. This frees up system resources and lets other programs access the file.
  5. Finally, implement the toString method to return a String with the "short" representation of all the courses, one per line. This will help you verify that the courses were loaded correctly.

    • The toString method of a Course object will return its short representation (e.g., CS159 (3)).

Test your implementation by running the main method in CourseCatalog. It should load the courses from subset.txt and print them out:

CS149 (3)
CS159 (3)
CS227 (3)
MATH231 (3)
MATH235 (4)
...

Part 2: Searching for a Course

Now, implement the remaining two methods in the CourseCatalog class:

  • findCourse(String subject, int number): This method should search the courses list for a course with the specified subject and number. If found, it should return the Course object; otherwise, it should return null.
    • Iterate over the courses list, and for each course, check if its subject and number match the specified values.
    • If a match is found, return that Course object immediately.
    • If no match is found after checking all courses, return null.
  • findAllCoursesWithCredits(int credits): This method should return an ArrayList of all courses that have the specified number of credits.
    • You will need to create a new ArrayList<Course> to store the matching courses.
    • Iterate over the courses list, and for each course that matches the specified credits, add it to the new list.
    • Finally, return the new list.

Test your implementation by running the main method in CourseCatalog again. It should print out the results of the searches:

...
Found course: CS159 (3)
4 credit courses: [MATH235 (4)]

Test with the Full Dataset

Finally, test your program with the all_courses.txt file to ensure it can handle a larger dataset.

  1. In the main method, take a look at where the filename is specified.
    • Note the format of the path! It's relative to the cs159 folder.
    • Thus, it starts with src/labs/lab06/.
  2. Change the filename from subset.txt to all_courses.txt.
  3. Instead of printing out the whole catalog, just print out the total number of courses loaded.
    • System.out.println(catalog.getCourseCount());
  4. Same with the 4 credit courses; just print out the number of them.
    • System.out.println(fourCreditCourses.size());
  5. Run the program again to see if it correctly loads and processes all the courses.
3330
Found course: CS159 (3)
4 credit courses: 112

Submission

Submit your completed CourseCatalog.java file to Gradescope.