FileReader and FileWriter classes
FileReader class
FileWriter class
The PrintWriter class
Constructor method
Instance methods
Example
The BufferedReader class
Constructor method
Instance methods
Example
The StringTokenizer class
Exercise
Earlier we saw the FileInputStream and FileOutputStream classes to work with files as a sequence of bytes. The java.io package also provides two other classes, FileReader and FileWriter, that work with files as a sequence of characters instead.
(This distinction between bytes and characters may seem a bit pedantic, given that the major operating systems of today use ASCII - and so characters and bytes are almost synonymous. But Java uses the Unicode character set (where a character is 16 bits long), and so it needs to distinguish the two concepts.)
The FileReader class works analogously to the FileInputStream class: The only change is that the read() method works with an array of characters, rather than an array of bytes.
Similarly, the FileWriter class works analogously to the FileOutputStream class, except that the write() methods work with arrays of characters. (Also, the FileWriter constructor method throws an IOException instead of a FileNotFoundException - it's a minor change, but it can affect the program code.)
Using FileWriter for saving into a file is pretty inconvenient: The FileWriter methods take arrays of characters as parameters, but generally we just want to print a value into the file. The java.io library provides class called PrintWriter that we can layer on top of a FileWriter, to work with the file the way we actually want to work.
The constructor method for a PrintWriter takes a FileWriter as a parameter.
(Technically, the PrintWriter constructor actually takes a Writer object as a parameter, an abstract class which FileWriter extends. There are other classes that also extend the Writer class, and PrintWriter can be layered on top of any of these.)
The PrintWriter instance methods are as follows.
This allows us to save into a file just as conveniently as we can print to the screen. As an example, the following program would create a table of numbers and their square roots.
Notice how the PrintWriter methods don't throw exceptions, so that the only the process of opening the file needs to go into the try block.import java.io.*; public class SqrtTable { public static void main(String[] args) { PrintWriter file; try { if(args.length != 1) { System.err.println("usage: java SqrtTable filename"); return; } file = new PrintWriter(new FileWriter(new File(args[0]))); } catch(IOException e) { System.err.println("Error opening file " + args[0] + ": " + e.getMessage(); return; } for(int i = 1; i < 10; i++) { file.print(i); file.print(" "); file.print(Math.sqrt((double) i)); } file.close(); } }
Like PrintWriter is layered on top of a FileWriter, so the BufferedReader is layered on top of a FileReader.
There are just two instance methods worth knowing about in the BufferedReader class.
The following program takes a file name from the command line, reads the file into memory, and then prints it out with the lines in reverse order.
import java.util.*; import java.io.*; public class Reverse { public static void main(String[] args) { BufferedReader file; try { if(args.length != 1) { System.err.println("usage: java Reverse filename"); return; } file = new BufferedReader(new FileReader(new File(args[0]))); } catch(FileNotFoundException e) { System.err.println("Error opening file " + args[0] + ": " + e.getMessage(); return; } Vector lines = new Vector(); try { while(true) { String line = file.readLine(); if(line == null) break; lines.addElement(line); } file.close(); } catch(IOException e) { System.err.println("Error reading file: " + e.getMessage()); return; } for(int i = lines.size() - 1; i >= 0; i--) { System.out.println(lines.elementAt(i)); } } }
The final class we're going to look at isn't part of the java.io package at all - it's part of the java.util package. It's basic purpose is to break a string into tokens - basically, breaking it into words.
Breaking a string into tokens is often often handy when you're reading from a file: You often don't particularly care about the space separating the tokens, you just want to get the data within the tokens.
After creating a StringTokenizer object, you can use the following instance methods to get information about the tokens.
As an example, the following program would read a line from the user and print out all the words the user typed.
import java.util.*; import csbsju.cs160.*; public class PrintWords { public static void main(String[] args) { IO.print("Line: "); String line = IO.readLine(); StringTokenizer tokens = new StringTokenizer(line); while(tokens.hasMoreTokens()) { IO.println(tokens.nextToken()); } } }