# 4.6 Using Text Files

Each coding exercise has its own folder. Open its `.java` file and press **Run** to try it. **Run Tests** checks every graded exercise in this lesson at once.

Files are used to store data in software that we use every day. For example, when you play a game on your computer, your game progress is saved in a file. The next time you play that game, your game progress is loaded in from that file, so you can continue where you left off. In this lesson, you will learn how to read in data from a file in Java.

A **file** is storage for data that *persists* when the program is not running. The data in a file can be retrieved during program execution. For example in a previous lesson, you created a `SpellChecker` class that reads in a dictionary file into an array of words, and a `spellcheck` method that uses this array to verify if a word is spelled correctly. Input files like the dictionary enable us to handle large amounts of data efficiently. Instead of manually entering data into our program every time it runs, we can store the data in a file and read it as needed. Another benefit of using files is the ability to separate the data from the code, allowing for more modular and flexible software design.

## Java `File`, `Scanner`, and `IOException` Classes

A file can be connected to the program using the `File` and `Scanner` classes. These classes must be imported in from libraries; the `Scanner` class is in the `java.util` package and `File` is in the `java.io` package ( `io` stands for **input/output**).

A file can be opened by creating a `File` object, using the name of the file or the complete path to the file, as the argument of the constructor, for example `str` is the pathname to the file like “data.txt” in `new File(String str)`.

```java
import java.io.*;
...
File myFile = new File("data.txt");
```

After opening a file, the `Scanner` class can be used to read in the data from the file line by line. The `Scanner` class is part of the `java.util` package and has a constructor that takes a `File` object as an argument to create an input stream from the file.

But what if you misspell the file name or the file does not exist? The `Scanner` constructor will throw a `FileNotFoundException` if it cannot find the file. This is a type of `IOException`, which is a general error that is also thrown when the input does not match expectations. We’ve seen other exceptions before, like `ArrayIndexOutOfBoundsException` and `NullPointerException`. Exceptions are a way for Java to handle runtime errors that occur during program execution. When an exception is thrown, the program stops executing and the exception is *thrown* back to the calling method. If the exception is not handled, the program will terminate.

When using the `File` class, Java requires that you indicate what to do if the file with the provided name cannot be opened. Java uses `try/catch` blocks to handle exceptions, but you can use the `throws` keyword in the method header to indicate that the method may throw an exception instead of handling it there. One way to accomplish this is to add `throws IOException` to the header of the method that uses the file. If the file name is invalid, the program will terminate. The **throws IOException** statement is added to the end of the method header. Here is an example that sets up an input file in the main method and throws an exception.

```java
import java.io.*;
import java.util.*;

public class FileIO
{
                                          // Notice throws IOException here
   public static void main(String[] args) throws IOException
   {
      File myFile = new File("data.txt");
      Scanner scan = new Scanner(myFile);
      ...

      scan.close();
   }
}
```

Try the following exercise to practice reading in a file. Notice the compiler error “unreported exception FileNotFoundException; must be caught or declared to be thrown”. Add **throws IOException** to the end of the main method header to fix the error.

### Exercise 1

Run the code to see the error message. Add **throws** and the correct exception to the end of the main method header to fix the error.

> Open the `01-throws-exception-exercise` folder and edit `FileIO.java`. Press **Run** to try it; **Run Tests** checks it (2 tests).

Java forces programmers to handle exceptions because runtime errors can crash programs. The `throws` keyword is used to indicate that a method may throw an exception and assumes that it will be handled somewhere else. A better way to handle exceptions is to use `try/catch` blocks. These are not used in the AP CSA exam, but you will see them in professional Java code. Here is an example of a try/catch block that catches the `FileNotFoundException` exception. Notice that it is similar to an if/else statement that could be used for error-handling. You put the code that may cause an exception in a try block (the Java compiler will let you know if it is needed), and the code that handles the exception in a catch block. If the file is not found, the appropriate catch block will be executed, and the program will terminate. It can print out the exception message or do something else to handle the exception. You will not use try/catch in the AP CSA exam, but here is an example with more information available here [https://www.w3schools.com/java/java_try_catch.asp](https://www.w3schools.com/java/java_try_catch.asp).

```java
try
{
    Scanner scan = new Scanner(myFile);
}
catch (FileNotFoundException e)
{
    System.out.println("File not found!");
}
```

## Reading in Data with Scanner

Once the file is opened, the data can be read using `Scanner` methods. For example, the method, `nextLine` will read the next line of input and returns it as a `String`. Here are the methods used in the Scanner file to read all types of input (also on page 2 of the [Java Quick Reference](https://apcentral.collegeboard.org/media/pdf/ap-computer-science-a-java-quick-reference.pdf) provided during the AP exam):

- `Scanner(File f)` the Scanner constructor that accepts a File for reading.
- `String nextLine()` returns the next line of text up until the end of the line as a String read from the file or input source; returns null if there is no next line.
- `String next()` returns the next String up until a white space is read from the file or input source.
- `int nextInt()` returns the next int read from the file or input source. If the next `int` does not exist, it will result in an `InputMismatchException`. Note that this method does not read the end of the line, so the next call to `nextLine()` will return the rest of the line which will be empty.
- `double nextDouble()` returns the next double read from the file or input source. If the next `double` does not exist, it will result in an `InputMismatchException`.
- `boolean nextBoolean()` returns the next Boolean read from the file or input source. If the next `boolean` does not exist, it will result in an `InputMismatchException`.
- `boolean hasNext()` returns true if there is a next item to read in the file or input source; false otherwise.
- `void close()` closes the input stream.

The `Scanner` class can be used to read input from the keyboard or from a file. Here’s an example of the `nextInt` method being used to read from the keyboard.

### Exercise 2

The code will read in the 2 numbers in `input.txt` and multiply them. Try changing the input in `input.txt` to decimal numbers like 2.5 and run to see the `InputMismatchException`. Then, change the code to use `nextDouble()` instead of `nextInt()` and change the variables to type `double` to read in decimal numbers.

> Open the `02-calculatorInput` folder and edit `Multiply.java`. Press **Run** to try it; **Run Tests** checks it (2 tests). **Run** feeds it the input in `input.txt`; change that file to try other input. Its tests check your code, not what it prints: “Code contains `nextDouble()`”, “Code contains `double`”.

Notice that the `nextInt()` and `nextDouble()` methods read in a number but leave any space or newline characters on the input stream. This can cause problems if you have input to read in multiple lines. Using `nextLine` and the other `Scanner` methods together on the same input source sometimes requires code to adjust for the methods’ different ways of handling whitespace. Java programmers will often add in an extra call to `scan.nextLine();` to read in the rest of the line after reading in a number.

## Loop to Read in a File

A `while` loop is usually used to read in a file with multiple lines. The loop can use the method `hasNext` as the loop condition to detect if the file still contains elements to read. A loop with this condition will terminate when there are no more lines to read in the file. After the loop is finished reading the data, the `close` method from Scanner should be called to close the file.

```java
while (scan.hasNext())
{
   String line = scan.nextLine();
   ...
}
scan.close();
```

### Exercise 3

Complete the code to read in all of the dictionary file using a while loop. This code will also tell you how many lines are in the file.

> Open the `03-loop-read-file` folder and edit `FileIOLoop.java`. Press **Run** to try it; **Run Tests** checks it (3 tests).

## Save File Data into an Array

We can save a file line by line into an array. In the `SpellChecker` class, we read the data file of words into a dictionary array with the following code. Note that we had to know the number lines or words in the file to declare an array of the right size. We’ll learn about better data structures like the `ArrayList` in the next lessons where we do not need to know the size of the data in advance.

```java
String[] dictionary = new String[10000];
int i = 0;
while(scan.hasNext())
{
     String line = scan.nextLine();
     dictionary[i] = line;
     i++;
 }
```

The following exercise reads in a data file about Pokemon and prints out the first 10 lines in the file. This file has the extension *csv* which stands for **Comma Separated Values**. All spreadsheets can be saved as CSV text files, and spreadsheet software can easily open CSV files as spreadsheets. You can take a look at the [pokemon.csv](https://runestone.academy/ns/books/published/csawesome2/external/_static/datasets/pokemon.csv) file.

The data file `pokemon.csv` is in each exercise folder that uses it.

### Exercise 4

Complete the code in the main method to read in the first 10 lines of the pokemon file using the Scanner class, save each line into the pokemonLines array, and print it out. Make sure you check that the line counter i is less than 10 in the condition of the loop.

> Open the `04-read-pokemon-file` folder and edit `ReadData.java`. Press **Run** to try it; **Run Tests** checks it (4 tests).

## Split Strings

If you take a look at the Pokemon CSV file, you’ll notice that each line contains multiple data attributes separated by commas. These attributes include each Pokemon’s name, type, speed, etc. on each row. Typically, the first line of a CSV file serves as the header, indicating the names of these attributes.

```
// The first line of the Pokemon CSV file
Number, Pokemon, Type 1, Type 2, HP, Attack, Defense, Speed, PNG, Description
```

The Java `String` class provides a useful method called `split(String delimeter)` that splits a string into an array of substrings based on a specified **delimiter** which is a character like a comma or a space that separates the units of data. This method returns a `String` array where each element in the array represents a field of data from the line.

```java
String sentence = "A quick brown fox jumps";
// Split the sentence into words along spaces to create:
//  words = {"A", "quick", "brown", "fox", "jumps"}
String[] words = sentence.split(" ");
```

Here is an example of how to use the split method to split a line of data with commas separating the fields from the Pokemon csv file into identifiable chunks of data. The first line of headers in the file indicates that the 0th element of the data array is the Pokemon’s number, element 1 is the name, etc. We only need to save the data that we want to use. In this case, we want to save the name, type1, speed, and imageFile. If we want to do math or comparisons with the speed, we can convert it to an int using the `Integer.parseInt` method that will be described in the next lesson.

```java
// Split the line of data into an array of Strings
String[] data = line.split(",");
// Identify the data
// data: Number,Name,Type1,Type2,HP,Attack,Defense,Speed,PNG,Description
String name = data[1];
String type1 = data[2];
...
String speed = data[7];
String imageFile = data[8];
```

Try the exercise below to display Pokemon images using the `split` method to extract names and urls saved in the file. Note that in the program below, the `readFile` method may throw an `IOException` to the calling method `main`, so both method headers must have the `throws IOException` clause.

### Exercise 5

**PokeImages:** This program reads in some of the data from the pokemon file into a String array of lines. Complete the `randomPokemon` method to print out a random pokemon name and its image using the split method. Run the program multiple times to see different Pokemon names and images.

> Open the `05-pokeImages` folder and edit `PokeImages.java`. Press **Run** to try it; **Run Tests** checks it (6 tests). Its tests check your code, not what it prints: “Code contains `(int)(Math.random()*length`”, “+ 1 in Math.random() line”, “call to split method”, “call to ImageHelper.showImage”, “the correct index for the name (1)”, “the correct index for the image url (8)”. It draws pictures: **Run** saves the drawing as an image in its folder, and **Run Tests** checks the code without the drawing.

## Object-Oriented Design with CSV Files

To better organize and work with this data, we can create a `Pokemon` class that corresponds to these attributes using object-oriented design. A CSV data file can be saved into an array of `Pokemon` objects by splitting each line (except the header) into the attributes for one `Pokemon` object.

We can use the `split` method to extract the individual pieces of data from each line of the CSV file and save this data into a `Pokemon` object. We must first create a `Pokemon` class with instance variables that correspond to the data attributes, and a constructor that initializes these variables. Assuming that we have already written the `Pokemon` class and constructor, the following code creates a Pokemon object from the data using its constructor and saves it into an array of `Pokemon` objects.

```java
// Create an array of Pokemon objects
Pokemon[] pokemonArray = new Pokemon[152];

int i = 0;
while (scan.hasNext())
{
    String line = scan.nextLine();
    // Split each line into its attributes name, type1, etc.
    String[] data = line.split(",");
    String name = data[1];
    String type1 = data[2];
    ...
    String speed = data[7];
    String imageFile = data[8];

    // Create a Pokemon object from the split data
    Pokemon p = new Pokemon(name, type1, speed, imageFile);
    // Save p in the array
    pokemonArray[i] = p;

    i++;
}
```

Note that sometimes you may need to skip the 0th row in the file if it is column headers. For this file, it will just get split into strings, but if your data file contains numbers that need to be processed, you could skip one like: `if (i == 0) scan.nextLine();`.

Let’s try the code to read into an array of Pokemon objects in the challenge exercise below.

## Coding Challenge: Array of Pokemon from Input File

Let’s end with a challenge that combines all the skills you have learned so far. You could work in pairs for this challenge. Create a class Pokemon that has at least 3 attributes that can be found in the Pokemon file, including its name, type1, and imagefile, and any other attributes from the file that you would like. Write a constructor and getters for these attributes. Then, read in the data from the pokemon file, split each line, and save the data in an array of Pokemon objects. Write a `findType` method that returns to the type of a Pokemon given its name as an argument. It should loop through the array to find the right Pokemon object using the `getName` and `getType` methods that you will write. It should also display the image for the Pokemon.

### Exercise 6

Design the class Pokemon that has at least 3 attributes that can be found in the Pokemon file, including its name, type1, and imagefile, and any other attributes from the file that you would like. Write a constructor and getters for these attributes. Then, read in the data from the pokemon file, split each line, and save the data in an array of Pokemon objects. Write a `findType` method that loops through the array to find the Pokemon with the given name as argument and print out and return its type and its image.

> Open the `06-challenge-pokemon-file` folder and edit `PokemonArray.java`. Press **Run** to try it; **Run Tests** checks it (5 tests). It draws pictures: **Run** saves the drawing as an image in its folder, and **Run Tests** checks the code without the drawing.

## Optional Challenge with a Dataset

If your class has time, you can try the following open-ended challenge that uses a dataset of your choice. You could work in pairs for this challenge. Choose a dataset from the files [pokemon.csv](https://runestone.academy/ns/books/published/csawesome2/external/_static/datasets/pokemon.csv), [WorldIndicators2000.csv](https://runestone.academy/ns/books/published/csawesome2/external/_static/datasets/WorldIndicators2000.csv), or [StateData2020-CDC-Census.csv](https://runestone.academy/ns/books/published/csawesome2/external/_static/datasets/StateData2020-CDC-Census.csv) to read into an array of objects. The exercise below is set up to use these files. Look at the columns of the dataset you have chosen in the exercise folder to decide on the name and at least 3 attributes for your class. Each row in the data file will be an object of your class that you will add to the array. If you find another data CSV file online that you would like to use, you can read from a URL instead of a file in Java using the `java.net` package following the directions here [https://docs.oracle.com/javase/tutorial/networking/urls/readingURL.html](https://docs.oracle.com/javase/tutorial/networking/urls/readingURL.html).

After you have chosen an input file, use the Pokemon exercise in the section above as a guide to:

1. Design a class for the input file that you have chosen. Choose at least 3 attributes that can be found in the file for your class. Write a constructor that takes in these attributes as parameters and saves them into instance variables. You may need to add some getters and a `toString` method as well.
2. Declare an array of your class type.
3. Read in the data from the file.
4. Inside a loop, split each line into its attributes and create an object for your class using its constructor. Add the object to the array.
5. Do something interesting with the data using a loop, for example you could find the maximum or minimum value of an attribute or print out all the objects that have the same attribute value.

### Exercise 7

**Input File Challenge:** Design the class for your input file that has at least 3 attributes that can be found in the file. Then, read in the data from the file, split each line, and save the data in an array of objects. Finally, do something interesting with the data using a loop, for example you could find the object with the max or min attribute value or print out all the objects of a certain attribute value. You can use the files pokemon.csv, WorldIndicators2000.csv, or StateData2020-CDC-Census.csv.

> Open the `07-challenge-file` folder and edit `Data.java`. Press **Run** to try it; **Run Tests** checks it (4 tests). Its tests check your code, not what it prints: “Number of private instance variables”, “call to split method”, “while loop”, “for loop”.

## Summary

- (AP 4.6.A.1) A **file** is storage for data that persists when the program is not running. The data in a file can be retrieved during program execution.
- (AP 4.6.A.2) A file can be connected to the program using the `File` and `Scanner` classes.
- (AP 4.6.A.3) A file can be opened by creating a `File` object, using the name of the file as the argument of the constructor. `File(String str)` is the `File` constructor that accepts a `String` file name to open for reading, where `str` is the pathname for the file.
- (AP 4.6.A.4) When using the `File` class, it is required to indicate what to do if the file with the provided name cannot be opened. One way to accomplish this is to add `throws IOException` to the header of the method that uses the file. If the file name is invalid, the program will terminate.
- (AP 4.6.A.5) The `File` and `IOException` classes are part of the `java.io` package. An `import` statement must be used to make these classes available for use in the program.
- (AP 4.6.A.6) The following `Scanner` methods and constructor—including what they do and when they are used—are part of the [Java Quick Reference](https://apcentral.collegeboard.org/media/pdf/ap-computer-science-a-java-quick-reference.pdf) (p. 2) provided during the AP CSA exam:
  > - `Scanner(File f)` the Scanner constructor that accepts a File for reading.
  > - `int nextInt()` returns the next int read from the file or input source. If the next `int` does not exist, it will result in an `InputMismatchException`. Note that this method does not read the end of the line, so the next call to `nextLine()` will return the rest of the line which will be empty.
  > - `double nextDouble()` returns the next double read from the file or input source. If the next `double` does not exist, it will result in an `InputMismatchException`.
  > - `boolean nextBoolean()` returns the next Boolean read from the file or input source. If the next `boolean` does not exist, it will result in an `InputMismatchException`.
  > - `String nextLine()` returns the next line of text up until the end of the line as a `String` read from the file or input source; returns the empty string if called immediately after another `Scanner` method like `nextInt` that is reading from the file or input source;returns null if there is no next line.
  > - `String next()` returns the next String up until a white space read from the file or input source.
  > - `boolean hasNext()` returns true if there is a next item to read in the file or input source; false otherwise.
  > - `void close()` closes the input stream.
- (AP 4.6.A.7) Using `nextLine` and the other `Scanner` methods together on the same input source sometimes requires code to adjust for the methods’ different ways of handling whitespace.
- (AP 4.6.A.8) The following additional `String` method—including what it does and when it is used—is part of the [Java Quick Reference](https://apcentral.collegeboard.org/media/pdf/ap-computer-science-a-java-quick-reference.pdf) provided during the AP CSA Exam:
  > - `String[] split(String del)` returns a `String` array where each element is a substring of `this String`, which has been split around matches of the given expression `del`.
  > - For example, `String[] data = line.split(",");` splits a line from a csv file along the commas and saves the substrings into the array `data`.
- (AP 4.6.A.9) A `while` loop can be used to detect if the file still contains elements to read by using the `hasNext` method as the condition of the loop.
- (AP 4.6.A.10) A file should be closed when the program is finished using it. The `close` method from `Scanner` is called to close the file.

The data file `WorldIndicators2000.csv` is in each exercise folder that uses it.

The data file `StateData2020-CDC-Census.csv` is in each exercise folder that uses it.
