Input / Output Chapter 13 We use files all the time Programs are files Documents are files We want them to be “permanent” To last beyond execution of a program We want to access and use them again A file can be input into or output from a program Open file Close file Create object Associate stream of bytes with it Make it no longer available to application Should always close every file you open Stream Bytes flowing into program from input device Bytes flow out of application to output device Most streams flow in only one direction A stream is an object that enables the flow of data between a program and some I/O device or file If the data flows into a program, then the stream is called an input stream If the data flows out of a program, then the stream is called an output stream Input streams can flow from the keyboard or from a file System.in is an input stream that connects to the keyboard Scanner keyboard = new Scanner(System.in); Output streams can flow to a screen or to a file System.out is an output stream that connects to the screen System.out.println("Output stream"); Files that are designed to be read by human beings, and that can be read or written with an editor are called text files Text files can also be called ASCII files because the data they contain uses an ASCII encoding scheme An advantage of text files is that the are usually the same on all computers, so that they can move from one computer to another Files that are designed to be read by programs and that consist of a sequence of binary digits are called binary files Binary files are designed to be read on the same type of computer and with the same programming language as the computer that created the file An advantage of binary files is that they are more efficient to process than text files File class – Gather file information java.io package Open a file File someData = new File("Data.txt"); File someData = new File("C:\\MyDocuments\\Data.txt"); import java.io.*; public class FileOpen { public static void main(String[ ] args) { File myFile = new File("Data.txt" ); if(myFile.exists( )) { System.out.println(myFile.getName( ) + " exists"); System.out.println(" The file is " + myFile.length( ) + " bytes long"); if (myFile.canRead( )) System.out.println("OK to read"); else System.out.println("not OK to read"); } else System.out.println("File does not exist"); } } The class Scanner can be used for reading from the keyboard as well as reading from a text file Simply replace the argument System.in (to the Scanner constructor) with a suitable stream that is connected to the text file Scanner SomeData = new Scanner(new File("Data.txt")); Methods of the Scanner class for reading input behave the same whether reading from the keyboard or reading from a text file For example, the nextInt and nextLine methods Write code to read data from a file: Imagine you are reading data from keyboard Put usual Scanner and next codes in program Add some extra items Add import declaration: import java.io.* Use java.io.File and java.io.IOException Type throws IOException into method header Type new File(“ “) into your call to new Scanner Type file name inside quotation marks Use next, nextLine, nextInt, etc import java.util.Scanner; import java.io.* public class FileOpen { public static void main(String[ ] args) throws IOException{ Scanner input = new Scanner(new File("Data.txt" )); String line1 = input.nextLine( ); String line2 = input.nextLine( ); System.out.println(line1); System.out.println(line2); } } How do we save data to a text file? We can produce an object of the class PrintWriter that is connected to the file FileName The process of connecting a stream to a file is called opening the file If the file already exists, then doing this causes the old contents to be lost If the file does not exist, then a new, empty file named FileName is created After doing this, the methods print and println can be used to write to the file PrintWriter Create an object using PrintWriter PrintWriter output = new PrintWriter("Data.txt")); We can now print to the text file using print or println Instead of System.out, we will use our new object output.println("This goes to our new file“); When a program is finished writing to a file, it should always close the stream connected to that file outputStreamName.close(); This allows the system to release any resources used to connect the stream to the file If the program does not close the file before the program ends, Java will close it automatically, but it is safest to close it explicitly Output streams connected to files are usually buffered Rather than physically writing to the file as soon as possible, the data is saved in a temporary location (buffer) When enough data accumulates, or when the method flush is invoked, the buffered data is written to the file all at once This is more efficient, since physical writes to a file can be slow The method close invokes the method flush, thus insuring that all the data is written to the file If a program relies on Java to close the file, and the program terminates abnormally, then any output that was buffered may not get written to the file Also, if a program writes to a file and later reopens it to read from the same file, it will have to be closed first anyway The sooner a file is closed after writing to it, the less likely it is that there will be a problem import java.io.* public class FileOutput { public static void main(String[ ] args) throws IOException{ PrintWriter listOut = new PrintWriter("List.txt"); listOut.println("This is our printout"); listOut.close( ); } } Data stored in a text file are represented in human-readable form. Data stored in a binary file are represented in binary form. You cannot read binary files. Binary files are designed to be read by programs. The advantage of binary files is that they are more efficient to process than text files. We can use Streams to handle binary files InputStream and OutputStream Abstract classes that contain methods for performing input and output One of the ways to improve the performance of a program that reads input streams is to buffer the input Buffering is the process of saving data in memory for use later when a program needs it When a Java program needs data from a buffered input stream, it looks in the buffer first, which is faster than reading from a source such as a file The class BufferedReader is a stream class that can be used to read from a text file An object of the class BufferedReader has the methods read and readLine A program using BufferedReader, like one using PrintWriter, will start with a set of import statements: import import import import java.io.BufferedReader; java.io.FileReader; java.io.FileNotFoundException; java.io.IOException; This stream class uses FileReader to convert the file name to an object that can be used as an argument A stream of the class BufferedReader is created and connected to a text file as follows: BufferedReader someData = new BufferedReader(new FileReader("Data.txt")); This opens the file for reading After these statements, the methods read and readLine can be used to read from the file The readLine method is the same method used to read from the keyboard, but in this case it would read from a file The read method reads a single character, and returns a value (of type int) that corresponds to the character read Since the read method does not return the character itself, a type cast must be used: char next = (char)(someData.read()); Unlike the Scanner class, the class BufferedReader has no methods to read a number from a text file Instead, a number must be read in as a string, and then converted to a value of the appropriate numeric type using one of the wrapper classes To read in a single number on a line by itself, first use the method readLine, and then use Integer.parseInt, Double.parseDouble, etc. to convert the string into a number If there are multiple numbers on a line, StringTokenizer can be used to decompose the string into tokens, and then the tokens can be converted as described above import java.io.* public class FileOpen { public static void main(String[ ] args) throws IOException{ BufferedReader input = new BufferedReader(new FileReader("Data.txt" )); String line1 = input.readLine( ); String line2 = input.readLine( ); input.close( ); System.out.println(line1); System.out.println(line2); } } Objects can also be input and output from a binary file Use the writeObject method of the class ObjectOutputStream to write an object to a binary file Use the readObject method of the class ObjectInputStream to read an object from a binary file The class ObjectInputStream is a stream class that can be used to read from a binary file An object of this class has methods to read strings, values of primitive types, and objects from a binary file A program using ObjectInputStream needs to import several classes from package java.io: import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; An ObjectInputStream object is created and connected to a binary file as follows: ObjectInputStream someData = new ObjectInputStream( new FileInputStream(("Data.txt")); The constructor for FileInputStream may throw a FileNotFoundException The constructor for ObjectInputStream may throw an IOException Each of these must be handled After opening the file, ObjectInputStream methods can be used to read to the file Methods used to input primitive values include readInt, readDouble, readChar, and readBoolean The method readUTF is used to input values of type String If the file contains multiple types, each item type must be read in exactly the same order it was written to the file The stream should be closed after reading Reading and writing strings and characters may need to be converted to binary components. The computer can handle Unicode which consists of two bytes: UTF-8 is a coding scheme that allows systems to operate with both ASCII and Unicode efficiently. Most operating systems use ASCII. Java uses Unicode. The ASCII character set is a subset of the Unicode character set. To construct a ObjectOutputStream, use the following constructors: FileOutputStream ("Data.txt") FileOutputStream ("Data.txt", boolean append) If the file does not exist, a new file would be created. If the file already exists, the first constructor would delete the current contents in the file. To retain the current content and append new data into the file, use the last constructor by passing true to the append parameter. Not all objects can be written to an output stream. Objects that can be written to an object stream is said to be Serializable The Serializable interface is easy to use and requires no knowledge of interfaces A class that implements the Serializable interface is said to be a serializable class In order to make a class serializable, simply add implements Serializable to the heading of the class definition public class SomeClass implements Serializable When a serializable class has instance variables of a class type, then all those classes must be serializable also A class is not serializable unless the classes for all instance variables are also serializable for all levels of instance variables within classes The streams for sequential access to files are the ones most commonly used for file access in Java However, some applications require very rapid access to records in very large databases These applications need to have random access to particular parts of a file The stream class RandomAccessFile, which is in the java.io package, provides both read and write random access to a file in Java A random access file consists of a sequence of numbered bytes There is a kind of marker called the file pointer that is always positioned at one of the bytes All reads and writes take place starting at the file pointer location The file pointer can be moved to a new location with the method seek Although a random access file is byte oriented, there are methods that allow for reading or writing values of the primitive types as well as string values to/from a random access file These include readInt, readDouble, and readUTF for input, and writeInt, writeDouble, and writeUTF for output The constructor for RandomAccessFile takes either a string file name or an object of the class File as its first argument The second argument must be one of four strings: "rw", meaning the code can both read and write to the file after it is open "r", meaning the code can read from the file, but not write to it RandomAccess someData = new RandomAccess( "Data.txt", "rw")); You are sitting behind the desk at the Java Hotel. Here comes a party of 4 and they would like a room. You need to check to see if a room is vacant. If one is, you then need to modify the guest list when you assign the room First let’s create the Guest list file import java.io.*; class GuestList { public static void main(String[ ] args) throws IOException{ int guests [] = {1, 4, 2, 0, 0, 2, 4, 1, 0, 1}; int roomNum; PrintStream listOut = new PrintStream("GuestList.txt"); for (roomNum = 0; roomNum < 10; roomNum++){ listOut.print(guests[roomNum]); listOut.print(" "); } listOut.close( ); } } Now we need to create the code to check for an available room We need to open and read the file We need to verify if a room is unoccupied We need to ask the how many in your party We need to update the GuestList file import java.util.Scanner; import java.io.*; class FindVacancy { public static void main(String[ ] args) throws IOException{ int guests [ ] = new int[10]; int roomNum; Scanner input = new Scanner(System.in); Scanner file = new Scanner(new File("GuestList.txt")); for (roomNum = 0; roomNum < 10; roomNum++) guests[roomNum] = file.nextInt(); // continued on next slide roomNum = 0; while (roomNum < 10 && guests[roomNum] != 0) roomNum++; if (roomNum == 10) System.out.println("Sorry, no vacancy"); else { System.out.println("How many people for room " + roomNum + " ?"); guests[roomNum] = input.nextInt( ); PrintStream listOut = new PrintStream("GuestList.txt"); for (roomNum = 0; roomNum < 10; roomNum++){ listOut.print(guests[roomNum]); listOut.print(" "); } } } }