File Input and Output
Tags: java, programming, learning, beginners
Published: 2024-06-14 11:29:33

Use the **Scanner** class for reading text data from a file and the **PrintWriter** class for writing text data to a file. A **File** object encapsulates the properties of a file or a path, but it does not contain the methods for creating a file or for writing/reading data to/from a file (referred to as data _input_ and _output_, or _I/O_ for short). In order to perform I/O, you need to create objects using appropriate Java I/O classes. The objects contain the methods for reading/writing data from/to a file. There are two types of files: text and binary. Text files are essentially characters on disk. This section introduces how to read/write strings and numeric values from/to a text file using the Scanner and PrintWriter classes.

## Writing Data Using PrintWriter

The **java.io.PrintWriter** class can be used to create a file and write data to a text file. First, you have to create a **PrintWriter** object for a text file as follows:

`PrintWriter output = new PrintWriter(filename);`

Then, you can invoke the **print**, **println**, and **printf** methods on the **PrintWriter** object to write data to a file. Figure below summarizes frequently used methods in **PrintWriter**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36vbeyklleaa34jzjqze.png)

The program below gives an example that creates an instance of **PrintWriter** and writes two lines to the file **scores.txt**. Each line consists of a first name (a string), a middle-name initial (a character), a last name (a string), and a score (an integer).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j20u9jmu9cfv0s79op74.png)

Lines 8–11 check whether the file scores.txt exists. If so, exit the program (line 10).

Invoking the constructor of **PrintWriter** will create a new file if the file does not exist. If the file already exists, the current content in the file will be discarded without verifying with the user.

Invoking the constructor of **PrintWriter** may throw an I/O exception. Java forces you to write the code to deal with this type of exception. For simplicity, we declare **throws IOException** in the main method header (line 6).

You have used the **System.out.print**, **System.out.println**, and **System.out.printf** methods to write text to the console. **System.out** is a standard Java object for the console output. You can create **PrintWriter** objects for writing text to any file using **print**, **println**, and **printf** (lines 17–20).

The **close()** method must be used to close the file (line 23). If this method is not invoked, the data may not be saved properly in the file.

##  Closing Resources Automatically Using try-with-resources

Programmers often forget to close the file. The followings new try-with-resources syntax automatically closes the files.

`try (declare and create resources) {
 Use the resource to process the file;
}`

Using the try-with-resources syntax, we rewrite the code in the program above, WriteData.java, in the program below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wg1ly86r57dy96up0wr.png)

A resource is declared and created followed by the keyword **try**. Note that the resources are enclosed in the parentheses (lines 12–15). The resources must be a subtype of **AutoCloseable** such as a **PrinterWriter** that has the **close()** method. A resource must be declared and created in the same statement and multiple resources can be declared and created inside the parentheses. The statements in the block (lines 15–21) immediately following the resource declaration use the resource. After the block is finished, the resource’s **close()** method is automatically invoked to close the resource. Using try-with-resources can not only avoid errors but also make the code simpler.

## Reading Data Using Scanner

A **Scanner** breaks its input into tokens delimited by whitespace characters. To read from the keyboard, you create a **Scanner** for System.in, as follows:

`Scanner input = new Scanner(System.in);`

To read from a file, create a **Scanner** for a file, as follows:

`Scanner input = new Scanner(new File(filename));`

Figure below summarizes frequently used methods in **Scanner**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skqypvk64pzbz4k8z8b6.png)

The program below gives an example that creates an instance of **Scanner** and reads data from the file **scores.txt**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qt7tmeaj9q9ugwpqi6b.png)

Note that **new Scanner(String)** creates a **Scanner** for a given string. To create a **Scanner** to read data from a file, you have to use the **java.io.File** class to create an instance of the **File** using the constructor **new File(filename)** (line 8), and use **new Scanner(File)** to create a **Scanner** for the file (line 11).

Invoking the constructor **new Scanner(File)** may throw an I/O exception, so the **main** method declares **throws Exception** in line 6.

Each iteration in the **while** loop reads the first name, middle initial, last name, and score from the text file (lines 14–20). The file is closed in line 23.

It is not necessary to close the input file (line 23), but it is a good practice to do so to release the resources occupied by the file. You can rewrite this program using the try-with-resources syntax.

## How Does **Scanner** Work?

The **nextByte()**, **nextShort()**, **nextInt()**, **nextLong()**, **nextFloat()**, **nextDouble()**, and **next()** methods are known as _token-reading methods_, because they read tokens separated by delimiters. By default, the delimiters are whitespace characters. You can use the **useDelimiter(String regex)** method to set a new pattern for delimiters.

How does an input method work? A token-reading method first skips any delimiters (whitespace characters by default), then reads a token ending at a delimiter. The token is then automatically converted into a value of the **byte**, **short**, **int**, **long**, **float**, or **double** type for **nextByte()**, **nextShort()**, **nextInt()**, **nextLong()**, **nextFloat()**, and **nextDouble()**, respectively. For the **next()** method, no conversion is performed. If the token does not match the expected type, a runtime exception **java.util.InputMismatchException** will be thrown.

Both methods **next()** and **nextLine()** read a string. The **next()** method reads a string delimited by delimiters, and **nextLine()** reads a line ending with a line separator.

The line-separator string is defined by the system. It is **\r\n** on Windows and **\n** on UNIX. To get the line separator on a particular platform, use

`String lineSeparator = System.getProperty("line.separator");`

If you enter input from a keyboard, a line ends with the _Enter_ key, which corresponds to the **\n** character.

The token-reading method does not read the delimiter after the token. If the **nextLine()** method is invoked after a token-reading method, this method reads characters that start from this delimiter and end with the line separator. The line separator is read, but it is not part of the
string returned by **nextLine()**.

Suppose a text file named **test.txt** contains a line

`34 567`

After the following code is executed,

`Scanner input = new Scanner(new File("test.txt"));
int intValue = input.nextInt();
String line = input.nextLine();`

**intValue** contains **34** and **line** contains the characters **' '**, **5**, **6**, and **7**.

What happens if the input is _entered from the keyboard_? Suppose you enter **34**, press the _Enter_ key, then enter **567** and press the _Enter_ key for the following code:

`Scanner input = new Scanner(System.in);
int intValue = input.nextInt();
String line = input.nextLine();`

You will get **34** in **intValue** and an empty string in **line**. Why? Here is the reason. The token-reading method **nextInt()** reads in **34** and stops at the delimiter, which in this case is a line separator (the _Enter_ key). The **nextLine()** method ends after reading the line separator and returns the string read before the line separator. Since there are no characters before the line separator, **line** is empty.

You can read data from a file or from the keyboard using the **Scanner** class. You can also scan data from a string using the **Scanner** class. For example, the following code

`Scanner input = new Scanner("13 14");
int sum = input.nextInt() + input.nextInt();
System.out.println("Sum is " + sum);`

displays

`The sum is 27`