This is a walkthrough of how to use File I/O. It will give a walkthrough of how to read from standard in, and how to read from and write to files. WRITING AND READING TO FILES ============================================================================ /O stands for "input and output." File I/O is reading from or writing to files on the disk. It should be noted that java treats network sockets like files as far as IO goes, like UNIX does. Although networking is not covered in this class, it is quite similar to accessing files on the disk. The standard input, standard error, and standard output are also very similar to files, and in fact the types for these three streams are found in java.io, along with the classes to perform other file operations. There are many slight variations in what needs to be done to perform File IO depending on what type of file is being dealt with and what needs to be done with it. We will first focus our attention on reading lines from a text file. The first thing that we should do is open the file in a FileReader (Note that we are creating a FileReader object): FileReader fr= new FileReader("myFile.txt"); The next thing that we should do is to wrap the FileReader in a BufferedReader: BufferedReader br= new BufferedReader(fr); This code creates a BufferedReader which will ask fr what is in the file and return it to the program line by line. The designers of Java decided to use this wrapper class concept to allow a lot of flexibility without having to create hundreds of different classes. Sometimes people will accomplish the above in one statement where perhaps the "wrapper" idea will be more obvious: BufferedReader has, among other methods, the method String readLine() which returns the next line of text from the file without the '\n' on the end- this method also automatically goes to the next line, so the next call to readLine() will give the next line, not the same one. When the program is done reading from the file, it should call the close method on the BufferedReader (which will close the underlying FileReader) so that the associated file resources may be freed (note that while memory is garbage collected, other resources, such as file descriptors are not). The above code, must of course have the exceptions dealt with properly, but that will be discussed in a minute. The other major operation that we will concern ourselves with is writing lines of text to a file. This can be accomplished similarly via the use of the FileWriter and PrintWriter classes: FileWriter fr=new FileWriter("output.txt"); PrintWriter pr= new PrintWriter(fr); The PrintWriter class has print() and println() methods which are overloaded to accept just about any paramter type and write it to the underlying FileWriter. It should be noted that print and println do NOT throw exceptions if a problem occurs while writing to the underlying file- instead, they just set an error variable in the PrintWriter instance, which may be checked with the checkError() method. The FileWriter class, may throw an exception when created, as described later. The PrintWriter must also be closed when the program is finished with it. If an output stream in not closed, then not only will the resources not be freed, but also, the data will never actually be written out to the disk, as it is buffered in memory, and flushed only when a certain amount is present, or the close() or flush() method gets called. So why do we need to deal with these extra classes? Why can't we just have one class to do it all? And how do these classes interact? Each class does a specific job and provides a certain ammount of modularity and abstraction. Lets look at the FileReader and BufferedReader: FileReader- has the job of reading characters from a file and assumes that the characters use default encoding. BufferedReader- has the job of reading text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. there are other classes that could be put into a BufferedReader, for example, an InputStreamReader- which basically reads from a byte stream and converts to a character stream, using some encoding scheme, which may be specified. So for example, if the file that you wanted to read used a different Unicode encoding scheme than the default for your system (maybe you are writing some international buisness software), then you would instead need to make a FileInputStream, wrap that in an InputStreamReader, then wrap that in a BufferedReader. In general, "Stream" deals with bytes, whereas "Reader" deals with characters. This abstraction gives the input classes more flexibility, in that they can also be used to allow for reading from other input streams than those avaiable from files on the disk- a network connection provides an instance of InputStream to read incoming data from the connection- InputStreams (as just mentioned) deal with bytes- if the program wants to read lines of text, for example, the same wrapping can be performed with the same classes to get a BufferedReader to give lines of text at a time from the network WRITING AND READING OBJECTS TO FILES ============================================================================ Writing and reading java objects to a file are slightly different than writing and reading Strings to file. First off, in order for a java Object to be able to be written to a file, it must implement Serializable. Only classes which implement the Serializable interface can be written to a file as an Object. To write an object to a file, you first need to create the Streams. The reason that you cannot use PrintWriter as you used before is because PrintWriter only can write Strings to a file. The two streams that need to be created are FileOutputStream and ObjectOutputStream. The constructor to FileOutputStream takes in the name of the file to write to as a String. If the file does not exist, it creates one. The constructor to ObjectOutputStream takes in the newly created FileOutputStream. After creating them, you can write the object to the ObjectOutputStream. If the ObjectOutputStream was called oos, then oos.writeObject(theObject); would write the object to file. After writing all object, make sure to flush the ObjectOutputStream and close the FileOutputStream. To read objects from a file, you need to create an ObjectInputStream and a FileInputStream. The constructors for these work similar to the writer. To actually read an object, do ois.readObject(). This will need to be casted to the actuall object that it is. If the file does not exist, it will throw a FileNotFoundException. When the end of the file is reached, it throws an EndOfFileException.