COMP 121 Week 6: Files and Streams Objectives To be able to read and write text files To become familiar with the concepts of text and binary formats To understand when to use sequential and random file access To be able to read and write objects using serialization Reading Text Files Scanner class Simplest way to read text To read a disk file: a FileReader object Use the FileReader object when constructing a Scanner object Construct FileReader reader = new FileReader("input.txt"); Scanner in = new Scanner(reader); Use Scanner methods to read data from file next, nextLine, nextInt, and nextDouble Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Writing Text Files To write to a text file, construct a PrintWriter object PrintWriter out = new PrintWriter("output.txt"); If file already exists, it is reset before the new data are written to it If file doesn't exist, a new, empty file is created Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Writing Text Files (continued) Use print and println to write to a PrintWriter out.println(29.95); out.println(new Rectangle(5, 10, 15, 25)); out.println("Hello, World!"); You must close a file when you are done processing it out.close(); Otherwise, some output may not be written to the disk file Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Example Program Reads all lines of a file and writes them to the output file, preceded by line numbers Can be used to number lines in a Java source file Sample input file Mary had a little lamb Whose fleece was white as snow. And everywhere that Mary went, The lamb was sure to go! Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Example Program (continued) Program produces the output file: /* /* /* /* 1 2 3 4 */ */ */ */ Mary had a little lamb Whose fleece was white as snow. And everywhere that Mary went, The lamb was sure to go! Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. LineNumberer.java import import import import java.io.FileReader; java.io.IOException; java.io.PrintWriter; java.util.Scanner; public class LineNumberer { public static void main(String[] args) { Scanner console = new Scanner(System.in); System.out.print("Input file: "); String inputFileName = console.next(); System.out.print("Output file: "); String outputFileName = console.next(); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. LineNumberer.java (continued) try { FileReader reader = new FileReader(inputFileName); Scanner in = new Scanner(reader); PrintWriter out = new PrintWriter(outputFileName); int lineNumber = 1; try { while (in.hasNextLine()) { String line = in.nextLine(); out.println("/* " + lineNumber + " */ " + line); lineNumber++; } } finally { out.close(); } } catch (IOException exception) { System.out.println("Error processing file:" + exception); } } } Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Question: What package includes the Scanner class (needed for the import statement)? Answer: java.util Text and Binary Formats Two ways to store data Text format Binary format Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Text Format Human-readable form Sequence of characters 1234567890 stored as 10 characters, one byte each Use Reader and Writer and their subclasses to process input and output For input: FileReader reader = new FileReader("input.txt"); For output: FileWriter writer = new FileWriter("output.txt"); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Reading a Single Character from a File (not using Scanner) Use read method of Reader class to read a single character the next character as an int or the integer -1 at end of file returns Reader reader = . . .; int next = reader.read(); char c; if (next != -1) c = (char) next; Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Binary Format Data items are represented in bytes 1234567890 in binary format is stored in 4 bytes (int) Use InputStream and OutputStream and their subclasses to read and write More compact and more efficient Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Binary Format For input: FileInputStream inputStream = new FileInputStream("input.bin"); For output: FileOutputStream outputStream = new FileOutputStream("output.bin"); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Reading a Single Byte from a File Use read method of InputStream class to read a single byte the next byte as an int or the integer -1 at end of file returns InputStream in = . . .; int next = in.read(); byte b; if (next != -1) b = (byte) next; Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Using Streams, Readers, and Writers Use read to read a single character or byte Use write to write a single character or byte read and write are the only input and output methods provided by the file input and output classes Each class has a very focused responsibility To read numbers, strings, or other objects, you combine stream, reader, and writer classes with other classes (like Scanner and Serializable) Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Random Access vs. Sequential Access Sequential access A file is processed a byte at a time, starting at the beginning of the file It can be inefficient Random access Allows access at arbitrary locations in the file Only disk files support random access System.in and System.out do not Each disk file has a special file pointer position You can read or write at the position where the pointer is pointing Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Random Access vs. Sequential Access Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. RandomAccessFile You can open a file either for Reading only ("r") Reading and writing ("rw") RandomAccessFile f = new RandomAcessFile("bank.dat","rw"); To move the file pointer to a specific byte f.seek(n); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. RandomAccessFile (continued) To get the current position of the file pointer: // Return type is "long" because files can be very large long n = f.getFilePointer(); To find the number of bytes in a file: fileLength = f.length(); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Using Random Access Files Give each “field” a fixed size that is sufficiently large to hold the largest value Every record has the same “fields” and is the same size Easy to skip quickly to a given record Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Using Random Access Files (continued) RandomAccessFile class stores binary data readInt and writeInt read/write integers (stored in 4 bytes) double x = f.readDouble(); f.writeDouble(x); readDouble and writeDouble read/write doubles (stored in 8 bytes) Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Example To find out how many bank accounts are in the file public int size() throws IOException { // RECORD_SIZE is 12 bytes: // 4 bytes for the account number and // 8 bytes for the balance return (int) (file.length() / RECORD_SIZE); } Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Example (continued) To read the nth account in the file public BankAccount read(int n) throws IOException { file.seek(n * RECORD_SIZE); int accountNumber = file.readInt(); double balance = file.readDouble(); return new BankAccount(accountNumber, balance); } Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Example (continued) To write the nth account in the file public void write(int n, BankAccount account) throws IOException { file.seek(n * RECORD_SIZE); file.writeInt(account.getAccountNumber()); file.writeDouble(account.getBalance()); } Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Object Streams ObjectOutputStream class can save entire objects to disk ObjectInputStream class can read objects back in from disk Objects are saved in binary format; therefore, you use streams Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Writing a BankAccount Object to a File The ObjectOutputStream saves all instance variables when writeObject is called BankAccount b = . . .; ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("bank.dat")); out.writeObject(b); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Reading a BankAccount Object From a File readObject returns an Object reference Need to remember the type of the object that you saved and use a cast ObjectInputStream in = new ObjectInputStream(new FileInputStream("bank.dat")); BankAccount b = (BankAccount) in.readObject(); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Reading an Object From a File readObject method can throw a ClassNotFoundException It is a checked exception You must catch or declare it Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Serializable Interface Objects that are written to an object stream must belong to a class that implements the Serializable interface class BankAccount implements Serializable { . . . } Serializable interface has no methods Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Serialization The process of saving objects to a stream Each object is assigned a serial number on the stream If the same object is saved twice, only serial number is written out the second time When reading, duplicate serial numbers are restored as references to the same object Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. SerialDemo.java import import import import import import java.io.File; java.io.IOException; java.io.FileInputStream; java.io.FileOutputStream; java.io.ObjectInputStream; java.io.ObjectOutputStream; /** This program tests serialization of a Bank object. If a file with serialized data exists, then it is loaded. Otherwise the program starts with a new bank. Bank accounts are added to the bank. Then the bank object is saved. */ public class SerialDemo { Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. SerialDemo.java (continued) public static void main(String[] args) throws IOException, ClassNotFoundException { Bank firstBankOfJava; File f = new File("bank.dat"); if (f.exists()) { ObjectInputStream in = new ObjectInputStream(new FileInputStream(f)); firstBankOfJava = (Bank) in.readObject(); in.close(); } else { firstBankOfJava = new Bank(); firstBankOfJava.addAccount(new BankAccount(1001, 20000)); Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. SerialDemo.java (continued) firstBankOfJava.addAccount(new BankAccount(1015, 10000)); } // Deposit some money BankAccount a = firstBankOfJava.find(1001); a.deposit(100); System.out.println(a.getAccountNumber() + ":" + a.getBalance()); a = firstBankOfJava.find(1015); System.out.println(a.getAccountNumber() + ":" + a.getBalance()); ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream(f)); out.writeObject(firstBankOfJava); out.close(); } } Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Summary When reading text files, use the Scanner class When writing text files, use the PrintWriter class and the print and println methods Close all files when you are done processing them A File object is used for a file or directory A File object can be passed into the constructor of a file reader, writer, or stream Streams access sequences of bytes. Readers and writers access sequences of characters Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Summary (continued) Use FileReader, FileWriter, FileInputStream, and FileOutputStream to read and write disk files The read method returns an integer (-1 at the end of the file) which you must cast to a char or byte Sequential access processes a file one byte at a time Random access allows access at arbitrary locations in a file without first reading the preceding bytes A file pointer is the position in a random access file Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Summary (continued) Object streams can be used to save and restore all instance fields of an object Objects saved to an object stream must belong to classes that implement the Serializable interface Horstmann, C. (2008). Big Java (3rd ed.). New York: John Wiley & Sons. Any Questions?