Notes on File Handling in Java Input and Output in Java The java.io package contains classes that perform input and output. In Java, I/O classes are differentiated according to the type of data being read or written. Types of data that are dealt in Java are mainly: o Byte-oriented Data o Numeric Data o Character Data Byte oriented and numeric data is written with output streams and read with input streams. Character data, that is text, is written with writers and read with readers. Whether you use streams or readers and writers depends on the type of data you're dealing with. All text data, especially non-ASCII text, should be passed through a reader or writer. The two main stream classes are java.io.InputStream and java.io.OutputStream. The two main reader and writer classes are java.io.Reader and java.io.Writer Above four specified classes are abstract base classes for many different subclasses with more specialized abilities. What is a Stream? A stream is a sequence of data of undetermined length. It's called a stream because it's like a stream of water that continues to flow. There's no definite end to it. In Java a stream is composed of discrete bytes. The bytes may represent chars or other kinds of data. They may come faster than you can handle them, or your thread may block while waiting for the next one to arrive. The key to processing the stream is a while loop that processes each piece of data, until you encounter the end-of-stream character or some other exceptional condition occurs. In Unix you type end-of-stream with Control-D. On Windows, you type end-of-stream with Control-Z. Java 2 defines two types of Streams: o Byte Streams o Character Streams For BIM V Semester Notes on File Handling in Java The Byte Stream Classes Most stream classes are part of the java.io package. The two main classes for handling byte streams of data are o java.io.InputStream o java.io.OutputStream. These are abstract base classes for many different subclasses with more specialized abilities, including: Input Streams Output Streams BufferedInputStream BufferedOutputStream ByteArrayInputStream ByteArrayOutputStream DataInputStream DataOutputStream FileInputStream FileOutputStream FilterInputStream FilterOutputStream ObjectInputStream ObjectOutputStream PipedInputStream PipedOutputStream PushBackInputStream PrintStream InputStream OutputStream The InputStream Class java.io.InputStream is an abstract class that contains the basic methods for reading raw bytes of data from a stream. Although InputStream is an abstract class, many methods in the class library are only specified to return an InputStream, so you'll often have to deal directly with only the methods declared in this class. The major methods defined inside this class are as follows: o public abstract int read() throws IOException o public int read(byte[] data) throws IOException o public int read(byte[] data, int offset, int length) throws IOException o public long o public int skip(long n) throws IOException available() throws IOException o public void close() throws IOException o public void mark(int readLimit) For BIM V Semester Notes on File Handling in Java o public void reset() throws IOException o public boolean markSupported() Notice that almost all these methods can throw an IOException. This is true of pretty much anything to do with input and output. The only exception is the PrintStream class which eats all exceptions. Reading bytes of data The basic read() method of the InputStream class reads a single unsigned byte of data and returns the int value of the unsigned byte. This is a number between 0 and 255. If the end of stream is encountered, it returns -1 instead; and you can use this as a flag to watch for the end of stream. public abstract int read() throws IOException Here's a simple program that echoes back what the user types at the command line. import java.io.*; public class Echo { public static void main(String[] args) { try { echo(System.in); } catch (IOException ex) { System.err.println(ex); } } public static void echo(InputStream in) throws IOException { while (true) { int i = in.read(); // -1 is returned to indicate the end of stream if (i == -1) break; // without the cast a numeric string like "65" would be printed instead of the character "A" char c = (char) i; System.out.print(c); } System.out.println(); For BIM V Semester Notes on File Handling in Java } } Reading many bytes of data The basic read() method reads a byte at a time. This is less than perfectly efficient. The following two overloaded variants read multiple bytes into an array of bytes. o public int read(byte[] data) throws IOException The above methodsreads enough bytes to fill array data o public int read(byte[] data, int offset, int length) throws IOException The above method reads length bytes from the input stream and stores them into the array data starting at position offset. These methods then return the number of bytes actually read. If the end of stream is encountered, -1 is returned. Counting the available bytes The available() method tests how many bytes are ready to be read from the stream without blocking. public int available() throws IOException Skipping bytes The skip() method reads a specified number of bytes and throws them away. public int skip(long n) throws IOException Marking and resetting It's often useful to be able to read a few bytes, and then back up and reread them. Three methods support this: o public void mark(int readLimit) o public void reset() throws IOException o public boolean markSupported() For BIM V Semester Notes on File Handling in Java The boolean markSupported() method returns true if this stream supports marking and false if it doesn't. Assuming the stream does support marking, the mark() method places a bookmark in the stream which you can return to later using the reset() method. There can be only one mark in the stream at any given time. Marking a second location erases the first mark. If marking is not supported, these methods throw IOExceptions. Closing Streams When you're done with a stream, you should close it to release any resources associated with the stream. Once the stream is closed attempts to read from it, will throw IOExceptions. You close a stream with the close() method: public void close() throws IOException The OutputStream Class The java.io.OutputStream class sends raw bytes of data to a target such as the console or a network server. However, many methods in the class library are only specified to return OutputStream rather than the more specific subclass. The methods defined within the OutputStream class are as follows: o public abstract void write(int b) throws IOException o public void write(byte[] data) throws IOException o public void write(byte[] data, int offset, int length) throws IOException o public void flush() throws IOException o public void close() throws IOException The write() methods send raw bytes of data to whomever is listening to this stream. Sometimes output streams are buffered by the operating system for performance. In other words, rather than writing each byte as it's written, the bytes are accumulated in a buffer ranging from several bytes to several thousand bytes. Then, when the buffer fills up, all the data is written at once. The flush() method forces the data to be written whether or not the buffer is full. This is not the same as the buffering performed by a BufferedOutputStream. That buffering is handled by the Java runtime. For BIM V Semester Notes on File Handling in Java This buffering is at the native OS level. However, a call to flush() should empty both buffers. The close() method closes the stream and releases any resources associated with the stream. After the stream is closed, attempts to write to it throw IOExceptions. Sample Program illustrating the methods of OutputStream class: import java.io.*; public class HelloOutputStream { public static void main(String[] args) { String s = "Hello World\r\n"; // Convert s to a byte array byte[] b = new byte[s.length()]; s.getBytes(0, s.length()-1, b, 0); try { System.out.write(b); System.out.flush(); } catch (IOException ex) { System.err.println(ex); } } } Input from Files The java.io.FileInputStream class represents an InputStream that reads bytes from a file. It has the following public methods: o public FileInputStream(String name) throws FileNotFoundException o public FileInputStream(File file) throws FileNotFoundException o public FileInputStream(FileDescriptor fd) o public int read() throws IOException o public int read(byte[] data) throws IOException o public int read(byte[] data, int offset, int length) throws IOException o public long skip(long n) throws IOException o public int available() throws IOException o public void close() throws IOException o public final FileDescriptor getFD() throws IOException For BIM V Semester Notes on File Handling in Java Except for the constructors and getFD(), these methods merely override the methods of the same name in java.io.InputStream. You use them exactly like you use those methods, only you'll end up reading data from a file. Examples of Input from Files import java.io.*; public class Type { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { FileInputStream fis = new FileInputStream(args[i]); byte[] b = new byte[1024]; while (true) { int result = fis.read(b); if (result == -1) break; String s = new String(b, 0, result); System.out.print(s); } // end while } // end try catch (FileNotFoundException ex) { System.err.println("Could not find file " + args[i]); } catch (IOException ex) { System.err.println(ex); } System.out.println(); } // end for } // end main } For BIM V Semester Notes on File Handling in Java Writing data to Files The java.io.FileOutputStream class represents an OutputStream that writes bytes to a file. It has the following public methods: o public FileOutputStream(String name) throws IOException o public FileOutputStream(String name, boolean append) throws IOException o public FileOutputStream(File file) throws IOException o public FileOutputStream(FileDescriptor fd) o public void write(int b) throws IOException o public void write(byte[] data) throws IOException o public void write(byte[] data, int offset, int length) throws IOException o public void close() throws IOException o public final FileDescriptor getFD() throws IOException Example of Output to Files import java.io.*; public class MultiType { public final static int BUFFER_SIZE = 4096; public static void main(String[] args) { FileOutputStream[] fos = new FileOutputStream[args.length]; for (int i = 0; i < args.length; i++) { try { fos[i] = new FileOutputStream(args[i]); } catch (IOException ex) { System.err.println(e); } } // end for try { byte[] buffer = new byte[BUFFER_SIZE]; while (true) { int result = System.in.read(buffer); if (result == -1) break; for (int i = 0; i < args.length; i++) { For BIM V Semester Notes on File Handling in Java try { fos[i].write(buffer, 0, result); } catch (IOException ex) { System.err.println(ex.getMessage()); } } // end for } // end while } // end try catch (IOException ex) { System.err.println(e); } } // end main } Appending data to files It's often useful to be able to append data to an existing file rather than overwriting it. To do this just pass the boolean value true as the second argument to the FileOutputStream() constructor. For example, o FileOutputStream fos = new FileOutputStream("16.html", true); import java.io.*; public class Append { public static final int BUFFER_SIZE = 1024; public static void main(String[] args) { FileOutputStream[] fos = new FileOutputStream[args.length]; for (int i = 0; i < args.length; i++) { try { fos[i] = new FileOutputStream(args[i], true); } catch (IOException ex) { System.err.println(e); } } // end for For BIM V Semester Notes on File Handling in Java byte[] buffer = new byte[BUFFER_SIZE]; try { while (true) { int result = System.in.read(buffer); if (result == -1) break; for (int i = 0; i < args.length; i++) { try { fos[i].write(buffer, 0, result); } catch (IOException ex) { System.err.println(ex); } } // end for } // end while } // end try catch (IOException ex) { System.err.println(ex); } for (int i = 0; i < args.length; i++) { try { fos[i].close(); } catch (IOException ex) { System.err.println(ex); } } // end for } // end main } Filter Streams concrete subclasses of InputStream and OutputStream somehow modify data read from an underlying stream rarely use these classes directly, but their subclasses are extremely important connect filter streams to an underlying stream that supplies the actual bytes of data by passing the original stream to the filter stream's constructor For BIM V Semester Notes on File Handling in Java Filter Stream Classes BufferedInputStream and BufferedOutputStream These classes buffer reads and writes by reading data first into a buffer (an internal array of bytes) Thus an application can read bytes from the stream without necessarily calling the underlying native method The data is read from or written into the buffer in blocks; subsequent accesses go straight to the buffer DataInputStream and DataOutputStream These classes read and write primitive Java data types and strings in a machine-independent way PrintStream PrintStream allows very simple printing of both primitive values, objects, and string literals It uses the platform's default character encoding to convert characters into bytes This class traps all IOExceptions. This class is primarily intended for debugging. System.out and System.err are instances of PrintStream. PushbackInputStream This input stream has a one byte pushback buffer so a program can unread the last character read The next time data is read from the stream, the "unread" character is re-read ObjectInputStream and ObjectOutputStream Subclasses of DataInputStream and DataOutputStream that can also serialize and deserialize Java objects to and from raw bytes Used by remote method invocation (RMI) and JavaBeans. For BIM V Semester Notes on File Handling in Java Buffered Streams The java.io.BufferedInputStream and java.io.BufferedOutputStream classes buffer reads and writes by first storing the data in a buffer (an internal array of bytes) Then the program reads bytes from the stream without calling the underlying native method until the buffer is empty. The data is read from or written into the buffer in blocks; subsequent accesses go straight to the buffer. The only real difference to the programmer between a regular stream and a buffered stream are the constructors: o public BufferedInputStream(InputStream in) o public BufferedInputStream(InputStream in, int size) o public BufferedOutputStream(OutputStream out) o public BufferedOutputStream(OutputStream out, int size) The size argument is the number of bytes in the buffer If a size isn't specified, a 512 byte buffer is used. Data Stream Classes The java.io.DataInputStream and java.io.DataOutputStream classes read and write primitive Java data types and Strings in a machine-independent way Generally you use a DataInputStream to read data written by a DataOutputStream. DataOutputStream declares these methods: o public DataOutputStream(OutputStream out) o public void write(int b) throws IOException o public void write(byte[] data, int offset, int length) throws IOException o public final void writeBoolean(boolean b) throws IOException o public final void writeByte(int b) throws IOException o public final void writeShort(int s) throws IOException o public final void writeChar(int c) throws IOException o public final void writeInt(int i) throws IOException o public final void writeFloat(float f) throws IOException o public final void writeDouble(double d) throws IOException o public final void writeBytes(String s) throws IOException o public final void writeChars(String s) throws IOException o public final void writeUTF(String s) throws IOException For BIM V Semester Notes on File Handling in Java o public final int size() o public void flush() throws IOException The size() method returns the number of bytes written to this data output stream. DataInputStream has these methods: o public DataInputStream(InputStream in) o public final int read(byte[] input) throws IOException o public final int read(byte[] input, int offset, int length) throws IOException o public final void readFully(byte[] input) throws IOException o public final void readFully(byte[] input, int offset, int length) throws IOException o public final int skipBytes(int n) throws IOException o public final boolean readBoolean() throws IOException o public final byte o public final int o public final short o public final int o public final char o public final int readByte() throws IOException readUnsignedByte() throws IOException readShort() throws IOException readUnsignedShort() throws IOException readChar() throws IOException readInt() throws IOException o public final long readLong() throws IOException o public final float readFloat() throws IOException o public final double readDouble() throws IOException o public final String readUTF() throws IOException o public static final String readUTF(DataInput in) throws IOException PushbackInputStream The PushbackInputStream class provides a pushback buffer so a program can "unread" bytes onto the stream These may be bytes the program has read from the stream or they may be bytes that come from somewhere else The next time data is read from the stream, the "unread" bytes are read. o public void unread(int b) throws IOException o public void unread(byte[] data, int offset, int length) throws IOException o public void unread(byte[] data) throws IOException By default the buffer is only one byte long, and trying to unread more than that throws an IOException. However you can change the default buffer size with the second constructor below: For BIM V Semester Notes on File Handling in Java o public PushbackInputStream(InputStream in) o public PushbackInputStream(InputStream in, int size) For BIM V Semester Notes on File Handling in Java The File Class The java.io.File class represents a file name on the host system. It attempts to abstract system-dependent file name features like the path separator character. There are two ways to reference a file, relative and absolute. Absolute addressing gives a complete path to a file, starting with the disk and working its way down. How this is represented varies from operating system to operating system. Here are some examples: o Unix: "/home/users/elharo/file1" o DOS: "C:\home\users\elharo\file1" o Mac OS 9: "Macintosh HD:home:users:elharo:file1" java.io.File can hold a directory name equally as well as a filename. File Constructors o public File(String path) o public File(String path, String name) o public File(File dir, String name) File Methods o public String getName() o public String getPath() o public String getAbsolutePath() o public String getParent() o public boolean exists() throws SecurityException o public boolean canWrite() throws SecurityException o public boolean canRead() throws SecurityException o public boolean isFile() throws SecurityException o public boolean isDirectory() throws SecurityException o public boolean isAbsolute() o public long lastModified() throws SecurityException o public long length() throws SecurityException o public boolean mkdir() o public boolean mkdirs() throws SecurityException o public boolean renameTo(File destination) throws SecurityException o public boolean delete() throws SecurityException For BIM V Semester Notes on File Handling in Java Examples of the File Methods import java.io.*; public class FileInfo { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { File f = new File(args[i]); if (f.exists()) { System.out.println("getName: " + f.getName()); System.out.println("getPath: " + f.getPath()); System.out.println("getAbsolutePath: " + f.getAbsolutePath()); System.out.println("getParent: " + f.getParent()); if (f.canWrite()) { System.out.println(f.getName() + " is writable."); } if (f.canRead()) { System.out.println(f.getName() + " is readable."); } if (f.isFile()) { System.out.println(f.getName() + " is a file."); } else if (f.isDirectory()) { System.out.println(f.getName() + " is a directory."); } else { System.out.println("What is this?"); } if (f.isAbsolute()) { System.out.println(f.getName() + " is an absolute path."); } else { System.out.println( f.getName() + " is not an absolute path."); } try { For BIM V Semester Notes on File Handling in Java System.out.println("Last Modified" + f.lastModified()); System.out.println(f.getName() + " is " + f.length() + " bytes."); } catch (IOException ex) { } } else { System.out.println("Can't find the file " + args[i]); } } } } File Dialogs The java.awt.FileDialog class is a subclass of java.awt.Dialog used for choosing a file to open or save. This class uses the host platform's standard open and save file dialogs. You won't add components to a FileDialog, or handle user interaction. You'll just retrieve the result which will be the name and directory of a file. There are three steps to using a FileDialog: 1. Create the FileDialog 2. Make the FileDialog visible. 3. Get the directory name and file name of the chosen file You create a FileDialog with the constructor public FileDialog(Frame parent, String title, int mode) The Frame is the parent of this file dialog mode is one of the two mnemonic constants FileDialog.LOAD or FileDialog.SAVE A typical use of this might look like FileDialog fd = new FileDialog(new Frame(), "Please choose the file to open:", FileDialog.LOAD); fd.setVisible(true); FileDialog fd = new FileDialog(new Frame(), For BIM V Semester Notes on File Handling in Java "Please choose a file:", FileDialog.LOAD); fd.show(); if (fd.getFile() != null) { File f = new File(fd.getDirectory(), fd.getFile()); } If the user cancels the save, both getDirectory() and getFile() return null. Be sure to check for this! Controlling File Dialogs fd.setDirectory("/usr/tmp"); setFilenameFilter(FilenameFilter fnf). Random Access Files Random access files can be read from or written to or both from a particular byte position in the file. The position in the file is indicated by a file pointer. There are two constructors in this class: o public RandomAccessFile(String name, String mode) throws IOException o public RandomAccessFile(File file, String mode) throws IOException The getFilePointer(), length(), and seek() methods allow you to determine and modify the point in the file at which reads and writes occur. Attempts to seek (position the file pointer) past the end of the file just move the file pointer to the end of the file. Attempts to write from the end of the file extend the file. Attempts to read from the end of the file throw EOFExceptions. o public long getFilePointer() throws IOException o public void seek(long pos) throws IOException o public long length() throws IOException Reads and writes use methods that work identically to the methods of the DataInputStream and DataOutputStream classes, except that you can set the position at which the read or write occurs between calls to the read and write methods. For BIM V Semester Notes on File Handling in Java Readers and Writers The java.io.Reader and java.io.Writer classes are abstract superclasses for classes that read and write character based data. The subclasses are notable for handling the conversion between different character sets. Readers and writers are based on characters, which can have varying widths depending on the character set being used. For example, o ASCII and ISO Latin-1 use one byte characters. o Unicode uses two byte characters. o UTF-8 uses characters of varying width between one and three bytes. Readers and writers know how to handle all these character sets and many more seamlessly. The java.io.Reader class The methods of the java.io.Reader class are deliberately similar to the methods of the java.io.InputStream class. However rather than working with bytes, they work with chars. Methods o public int read() throws IOException o public int read(char[] text) throws IOException o public abstract int read(char[] text, int offset, int length) throws IOException o public long skip(long n) throws IOException o public boolean markSupported() o public void mark(int readAheadLimit) throws IOException o public void reset() throws IOException o public abstract void close() throws IOException o public boolean ready() throws IOException The ready() method returns true if the Reader is ready to be read from, false if it isn't. Generally this means the underlying stream has available data. The java.io.Writer class The methods of the java.io.Writer class are deliberately similar to the methods of the java.io.OutputStream class. However rather than working with bytes, they work with chars. Methods For BIM V Semester Notes on File Handling in Java o public void write(int c) throws IOException o public void write(char[] text) throws IOException o public abstract void write(char[] text, int offset, int length) throws IOException o public void write(String s) throws IOException o public void write(String s, int offset, int length) throws IOException o public abstract void flush() throws IOException o public abstract void close() throws IOException The InputStreamReader Class The java.io.InputStreamReader class serves as a bridge between byte streams and character streams It reads bytes from the input stream and translates them into characters according to a specified character encoding. The encoding can be set in the constructor, or you can accept the platform's default encoding. o public InputStreamReader(InputStream in) o public InputStreamReader(InputStream in, String encoding) throws UnsupportedEncodingException For example, to attach an InputStreamReader to System.in with the default encoding: o InputStreamReader isr = new InputStreamReader(System.in); On the other hand if you wanted to read a file that had been encoded using UTF-8, you might do this: o FileInputStream fis = new FileInputStream("file.utf8.txt"); o InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); Methods o public String getEncoding(): The getEncoding() method returns a string containing the name of the encoding used by this reader. o public int read() throws IOException o public int read(char[] text, int offset, int length) throws IOException o public boolean ready() throws IOException o public void close() throws IOException The OutputStreamWriter Class The java.io.OutputStreamWriter class connects byte streams and character streams It writes bytes onto the underlying output stream after translating characters according to a specified character encoding. For BIM V Semester Notes on File Handling in Java The encoding can be set in the constructor, or you can accept the platform's default encoding. o public OutputStreamWriter(OutputStream out, String enc) throws UnsupportedEncodingException o public OutputStreamWriter(OutputStream out) For example, to attach an OutputStreamWriter to System.out with the default encoding: o OutputStreamWriter osw = new OutputStreamWriter(System.out); On the other hand if you wanted to write a file encoded in UTF-16, you might do this: o FileOutputStream fos = new FileOutputStream("file.utf16.txt"); o OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-16"); Methods: o public String getEncoding():The getEncoding() method returns a string containing the name of the encoding used by this writer. o public void write(int c) throws IOException o public void write(char[] text, int offset, int length) throws IOException o public void write(String s, int offset, int length) throws IOException o public void flush() throws IOException o public void close() throws IOException Reading Files The FileReader class reads text files using the platform's default character encoding and the buffer size. If you need to change these values, construct an InputStreamReader on a FileInputStream instead. Constructors o public FileReader(String fileName) throws FileNotFoundException o public FileReader(File file) throws FileNotFoundException o public FileReader(FileDescriptor fd) Eg: FileReader fr = new FileReader("36.html"); Writing Text Files The java.io.FileWriter class writes text files using the platform's default character encoding and the buffer size. If you need to change these values, construct an OutputStreamReader on a FileOutputStream instead. For BIM V Semester Notes on File Handling in Java Constructors o public FileWriter(String fileName) throws IOException o public FileWriter(String fileName, boolean append) throws IOException o public FileWriter(File file) throws IOException o public FileWriter(FileDescriptor fd) Buffering Reads for Better Performance The java.io.BufferedReader class is a subclass of java.io.Reader that you chain to another Reader class to buffer characters. This allows more efficient reading of characters and lines. The BufferedReader is also notable for its readLine() method that allows you to read text a line at a time. There are two constructors, one with a default buffer size of 8192 characters: o public BufferedReader(Reader in, int size) o public BufferedReader(Reader in) The one new method in this class is readLine(). o public String readLine() throws IOException This method returns a String that contains a line of text from a text file. \r, \n, and \r\n are assumed to be line breaks and are not included in the returned String. The following example reads a text file, line by line, and prints it to System.out: // Implement the Unix cat utility in Java import java.io.*; class Cat { public static void main (String args[]) { String thisLine; //Loop across the arguments for (int i=0; i < args.length; i++) { //Open the file for reading try { BufferedReader br = new BufferedReader(new FileReader(args[i])); while ((thisLine = br.readLine()) != null) { System.out.println(thisLine); } // end while } // end try For BIM V Semester Notes on File Handling in Java catch (IOException ex) { System.err.println("Error: " + ex.getMessage()); } } // end for } // end main } Buffering Writes for Better Performance The java.io.BufferedWriter class is a subclass of java.io.Writer that you chain to another Writer class to buffer characters. This allows more efficient writing of text. There are two constructors, one with a default buffer size of 8192 characters: o public BufferedWriter(Writer out) o public BufferedWriter(Writer out, int size) The one new method in this class is newLine(). This method that writes a platform dependent line terminator string, \n on Unix, \r on the Mac, \r\n on Windows. o public String newLine() throws IOException Serialization Serialization is the process of writing the state of an object to a byte stream Needed to implement RMI (Remote Method Invocation) where a Java Object on one machine is used to invoke a method of a Java object on a different machine Serialization can be perform on only those objects which implement Serializable interface This interface doesn’t define members but rather indicate that a class may be serialized Static variable and Transient variable are not saved when the serialized objects are saved Streams used to read and write objects are ObjectOutputStream and ObjectInputStream Constructor of ObjectOutputStream: o public ObjectOutputStream(OutputStream out) throws IOException Major methods of ObjectOutputStream: o void writeObject(Object obj) Constructor of ObjectInputStream: o public ObjectInputStream (InputStream in) throws IOException Major methods of ObjectInputStream: o Object readObject(Object obj) For BIM V Semester