Colorado State University Logo | CS 163/4: Java Programming (CS 1) Colorado State University Logo | CS 163/4: Java Programming (CS 1)
CS 163/4: Java Programming (CS 1)
Computer Science

Lab 11 - File IO

Important

From this point onward all coding assignments will be done by downloading files from Zybooks, editing them in an IDE like IntelliJ and uploading them back to Zybooks for grading.

Introduction to Lab

Today we will be discussing file input and output, or File I/O. File I/O allows us to use external files to read in data for our programs to use, including text files, csv (Comma Separated Value files), image files, and more. In addition to being able to read from files, File I/O also allows us to write to files and create permanent file output for our users.

File I/O

Java provides strong I/O support. There are multiple ways to do I/O in Java, however, in this lab we will be focusing on two main ways. One way for input and another for output. There are some common similarities in regards to input and output - more specifically, error handling.

Input (File Objects)

For this lab, we will be inputting files with the use of File Objects. File Objects are created just like any other object that we have seen before. The constructor for the File object takes a String that represents a path to a file that it wants to work with. The path of the file can be local or absolute.

If you haven’t heard file terminology like paths/directories before, here’s a quick explanation:

  • Directory - a folder, or container, of files
  • Path - the list specifying where a document exists on the computer, in the format “home/subdirectory/subdirectory/filename.fileExtension”.

  • An example of a local path would be, if a file resided in a project folder in your IDE. Since this file is local to the project, the path name for this file would be the file name itself. Sometimes local file paths are also referred to as “relative” paths.
  • However, if the file resided somewhere else outside of the project folder, the absolute path would need to be given. Absolute file paths typically begin from the user’s home folder, or the computer’s root directory.

If the file does not exist or cannot be found, Java will throw an exception (more on this later). Below is an example differentiating local and absolute path names for a file named Example.txt.

Local Path:
File fileObj = new File("Example.txt");

Absolute Path:
File fileObj = new File("~/users/Documents/Example.txt");

Once a File Object is initialized, methods can be used from its class to do input manipulation. However, we will not be using those methods in this lab, instead we will be using a Scanner. To learn more about File Objects, visit this link: File Java Doc

File and Scanner Objects

File and Scanner Objects work well together. As we have seen before, we can use a Scanner to parse input from a keyboard and save that input into variables. Scanners can also be used to parse through files. In order to do this, a Scanner Object must be made with an initialized File Object in its constructor. By having this, the Scanner’s methods such as .next() and .nextInt() can be used for parsing a file. Shown below is two ways to initialize a File and Scanner Object to parse a file. Both have the same result, one just has less code.

Option 1:
File fileObj = new File("Example.txt");
Scanner fileScanner = new Scanner(fileObj);
 
Option 2:
Scanner fileScanner = new Scanner(new File("Example.txt"));

Output (PrintWriter Objects)

For this lab, we will be outputting to files with the use of PrintWriter Objects.

File Objects are initialized in the same way as PrintWriter Objects. The PrintWriter constructor takes a local or absolute path to a filename. However, unlike the File Objects if the filename passed to the constructor does not exist, that file will be created in the path given.

PrintWriters have many methods that can output to a file. The most common ones you will see are .print() and .println(). Notice that these are similar to System.out.print() and System.out.println(). These function the same, however, instead of outputting to the console it outputs to a file.

PrintWriters must be closed after using them in order to output to a file. This must done after using the PrintWriter in order to flush the buffer, which means that all the output stored while using the PrintWriter is actually written to the file. Below is an example of using a PrintWriter. To learn more about PrintWriters, visit this link: PrintWriter Java Doc

PrintWriter output = new PrintWriter(new File("Example.txt"));
output.println("Hello, World!");
output.close(); //Closing the PrintWriter 

Try/Catch

When using File I/O there is some overhead in exception handling. When reading or writing to a file, exceptions can be thrown by Java, for reasons like a file not being found.

You have more than likely seen exceptions like “NullPointerException” or “ArrayIndexOutOfBounds” when writing your code. These exceptions happens in Java when the program runs into a problem that disrupts the normal flow of the program. When this happens, Java does not have a direct way to fix it and therefore the program terminates followed by a message to the console of what went wrong.

In File I/O, we must plan for how to handle these exceptions because of how easily they may occur. This is mainly due to the exception “FileNotFoundException” which can occur especially with File Objects (Exceptions also occur in PrintWriter constructors).

To deal with these exceptions, we surround the code that has a potential for an exception with a try/catch block. Try/Catch blocks work by putting the code that could cause an exception into the try portion of the block. This tells the Java compiler to try this code but know that it may throw an exception. If the program does throw an exception, then the catch portion of the block can catch the exception and do something about it. Typically, the stack trace is outputted to the console from the catch block. However, you could write code in the catch block that could execute. Below is an example.

File Objects
1
2
3
4
5
6
7
8
9
public static void main(String[] args){
    try{
        File fileObj = new File("Example.txt");
        Scanner fileScanner = new Scanner(fileObj); //Exception could occur if the file does not exist
    } catch(FileNotFoundException e){
        e.printStackTrace();
    }
    
}
PrintWriter Objects
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args){
    try{
        PrintWriter output = new PrintWriter(new File("Example.txt")); // Exception could occur in constructor
        output.println("Hello, World!");
        output.close(); 
    } catch(FileNotFoundException e){
        e.printStackTrace();
    }
    
}

ZyBooks Assignment

Part 1 readFile(String filename)

In this method you are passed a String with the name of a file. This method will read the file in line by line and store each line in a String array. This String array is then returned. An example is shown below.

File Contents:
Purple Rain by Prince
I never meant to cause you any sorrow
I never meant to cause you any pain
I only wanted one time to see you laughing
I only want to see you laughing in the purple rain

String Array Contents:
[0]: Purple Rain by Prince
[1]: I never meant to cause you any sorrow
[2]: I never meant to cause you any pain
[3]: I only wanted one time to see you laughing
[4]: I only want to see you laughing in the purple rain

In order to do this, you will need:

  • a String array
  • an int that keeps track of how many lines there are in a file
  • a File Object
  • a Scanner Object

Assume that the String array holds a max of 1000 elements. Notice that there are three lines of code written at the bottom. DO NOT MODIFY THESE LINES. This code is copying your String array into a new array with the same amount of elements as there are lines in the file. Since this code is written for you, it assumes that your String array is named lines and that the int that keeps track of the amount of lines is named lineCounter. You will loop through and parse this file with the use of the Scanner and File Object and store each line in the String array while also counting each line.

Hints

  • How can a Scanner be used to know when the file ends?
  • You will need a try/catch block.

Part 2 reverseFile(String[] parsedFile, String filename)

This method takes a String array that has lines of a file in it and a filename. This method will write the contents of the String array in reverse order to the file passed. The writing will be done with a PrintWriter. Here is an example.

String Array Content:
[0]: Purple Rain by Prince
[1]: I never meant to cause you any sorrow
[2]: I never meant to cause you any pain
[3]: I only wanted one time to see you laughing
[4]: I only want to see you laughing in the purple rain

Files Contents:
I only want to see you laughing in the purple rain
I only wanted one time to see you laughing
I never meant to cause you any pain
I never meant to cause you any sorrow
Purple Rain by Prince

Hint

  • You will need a try/catch block.

Part 3 logFile(String[] parsedFile, String filename)

This method takes a String array that has lines of a file in it and a filename. This method will write contents of the String array to a file. However, It will only write the lines that contain “LOG”. Other lines will be skipped over. Here is an example.

String Array Content:
[0]: LOG username: happy_cat31
[1]: password: MrMuffins1234
[2]: LOG username: sad_panda
[3]: password: BambooLover83

Files Contents:
LOG username: happy_cat31
LOG username: sad_panda 

Hints

  • What String method could help determine if a file contains “LOG”? String Java Doc
  • You will need a try/catch block.

Computer Science Department

279 Computer Science Building
1100 Centre Avenue
Fort Collins, CO 80523
Phone: (970) 491-5792
Fax: (970) 491-2466

CS 163/4: Java Programming (CS 1)

Computer Programming in Java: Topics include variables, assignment, expressions, operators, booleans, conditionals, characters and strings, control loops, arrays, objects and classes, file input/output, interfaces, recursion, inheritance, and sorting.