14.4 File/IO


InputStream and OutputStream

You can use a Scanner to read user input and print statements to display output. But what if you want to read input or write output from a separate file. You might have a list of 100 names that you want to use in your code (read input), or generate a list of numbers that you want to save in a file (write output).
For this type of input/output (i/o), you can use Java streams. To get input, you create an InputStream that attaches to the file. The data in the file enters the stream, and the stream can parse and interpret the data in different ways, depending on the subclass of InputStream you’re using. The FileInputStream and FileOutputStream classes are specific to file i/o.
FileInputStream takes either a File instance or the name of a file as a parameter.FileOutputStream accepts both as a parameter, as well, and if the file doesn’t exist, it will create one with the given name.
The File class stores a file name, and there are various methods associated with the File class that either return info about the file (file.exists(), file.canWrite(), etc.), or execute actions within your computer system related to it (file.delete() will actually delete the file from your computer, etc.).
All the stream classes you’ll need are in the java.io package (import java.io.*).

IOException Class

This package also contains specific exceptions that might occur if something goes wrong (FileNotFoundException, FileLoadException, EndOfStreamException, etc.). You’ll have to use exception handling (try/catch blocks) to ensure that you account for all possible errors. Exceptions caused by input/output errors are subclasses of the IOException class.
public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; File file = new File("names.txt"); try { in = new FileInputStream(file); out = new FileOutputStream("names_upper.txt"); int c; while ((c = in.read()) != -1) out.write( Character.toUpperCase((char) c) ); } catch (IOException e) { System.out.println("An IO Exception occurred."); e.printStackTrace(); // Prints error output stream. } finally { if (in != null) in.close(); if (out != null) out.close(); } }
In this code, the FileInputStream and the FileOutputStream are declared outside of the try block, so that the scope of the variables is the entire method. They are defined inside the try block so that if there is an error (FileNotFound, etc.), it is caught. This code only catches IOException instances (this class is found in java.io), so other exceptions will not be processed.
File streams only read raw data (bytes), not letters or words. There are other wrapper streams that can further parse these byte streams, which you’ll learn about later. For now, when you use the read() method to read the next character, you will receive a byte with the ASCII value of the character. This is why c is an int.
The method returns -1 if it reaches the end of the file (EOF), so the while loop repeats until the character it reads (c) equals -1.
The goal of this program is to write all the text in one file to a different file in all uppercase (Cat → CAT). So, we have to cast the byte we received as input to a character before turning it uppercase. The write() method automatically turns the character back into an integer, before writing the raw data to the file.

Closing Streams

Leaving the input stream open can use up resources, and leaving the output stream open might not save your output.
Code in the finally block will always execute after the try block (or catch block) exits. It’s good practice to close the file streams in the finally block, so that even if something goes wrong in the middle of your code and there is an unusual exit, you don’t leave the streams open.
Copyright © 2021 Code 4 Tomorrow. All rights reserved. The code in this course is licensed under the MIT License. If you would like to use content from any of our courses, you must obtain our explicit written permission and provide credit. Please contact classes@code4tomorrow.org for inquiries.