You are on page 1of 4

Input vs.

Output
We dene input and output from the perspective of the programmer. Input, Output and Exceptions

Byte vs. Character Streams


Java has two kinds of I/O streams: byte streams and character streams

COMS W1007 Introduction to Computer Science

Input is data that comes into the program, e.g., from a le or from the keyboard into a program variable. Ouput is data that goes out of the program, e.g., into a le or to the screen.

Byte streams operate on arbitrary binary data. The parent classes of byte streams are InputStream and OutputStream. Character streams operate on textual data. The parent classes of character streams are Reader and Writer.

Christopher Conway 24 June 2003

public abstract class InputStream { /* returns a value 0-255, * or -1 for end of input */ public abstract int read() ; /* read count bytes into buf at offset */ public int read(byte[] buf, int offset, int count) { ... } /* fill buf */ public int read(byte[] buf) { ... } public /* how public public } long skip(long count) { ... } many bytes are available? */ int available() { ... } void close() { ... }

public abstract class Reader { /* returns a value 0-65535, * or -1 for end of input */ public abstract int read() ; /* read count bytes into buf at offset */ public int read(char[] buf, int offset, int count) { ... } /* fill buf */ public int read(char[] buf) { ... } public long skip(long count) { ... } /* is there input ready? */ public boolean ready() { ... } public void close() { ... } }

public abstract class OutputStream { /* writes b as a byte */ public abstract void write(int b) ; /* write count bytes from buf at offset */ public void write(byte[] buf, int offset, int count) { ... } /* write the entire buf */ public void write(byte[] buf) { ... } /* write any buffered values */ public void flush() { ... } public void close() { ... } }

public abstract class Writer { /* writes ch as a char */ public abstract void write(int ch) ; /* write count bytes from buf at offset */ public void write(char[] buf, int offset, int count) { ... } /* write the entire buf */ public void write(char[] buf) { ... } public void write(String str, int offset, int count) { ... } public void write(String str) { ... { /* write any buffered values */ public void flush() { ... } public void close() { ... } }

Conversion Streams
Classes are provided that convert between byte and character I/O.

File Streams
The le streams (FileInputStream, FileOutputStream, FileReader and FileWriter) enable byte and character I/O with les. Each has a constructor that takes a le name String and returns the corresponding stream. If you give a le output stream the name of a le that doesnt exist, it will create the le, if possible.

InputStreamReader takes a byte input stream as its source and produces the equivalent character input. OutputStreamWriter take a byte output stream as its target and converts character output into the equivalent byte form.

Filter Streams
Some streams are dened by where they get their data (or put it); others are dened by what they do to the data.

Filter Streams: Examples


InputStream inFile = new FileInputStream("foo.gz") ; int data = inFile.read() ; /* data contains 1 byte of gzip compressed data. */ InputStream inFile2 = new GZipInputStream( inFile ) ; data = inFile2.read() ; /* data contains 1 byte of decompressed data. */ OutputStream outFile = new GZipOutputStream( new FileOutputStream("bar.gz") ) ; outFile.write(12) ; /* bar.gz contains 1 compressed byte of data. */

Buffered Streams
Not every lter stream has to transform the data. The buffered streams (BufferedInputStream, BufferedOutputStream, BufferedReader and BufferedWriter) make I/O more efcient by reading and writing in large blocks. Instead of one access to disk for every call to read or write, a buffered stream puts a chunk of data into a buffer in memory; calls to read or write act on the buffer until it runs out. Note: it is often necessary to call flush() to force output on a buffered output stream.

Ordinary streams read and write data from a particular source, e.g., a le, or a byte array. Filter streams process data that comes in from or goes out to another data stream, e.g., buffering streams, compressing/decompressing streams.

LineNumberReader
The LineNumberReader input stream wraps a character input stream and keeps track of lines read. The method getLineNumber() returns the number of lines seens so far.
LineNumberReader in = new LineNumberReader( new FileReader( "input.txt" ) ) ; String line ; while( (line = in.readLine()) != null ) { System.out.println("Line "+in.getLineNumber() +": "+line) ; }

Print Streams
The print output streams (PrintStream and PrintWriter) are lter streams that provide print and println methods that take any of the basic types as parameters. The print streams output character data, i.e., println(123) is output as "123" (a 6-byte character string). System.out and System.err are static PrintStream objects. System.in is an InputStream.

Data Streams
The data streams (DataInputStream and DataOutputStream) provide convenience methods for reading and writing all of the basic types as binary data. I.e., writeInt(123) is output as 123 (a 32-bit binary-encoded integer). The data stream methods are of the form readInt/writeInt, readBoolean/writeBoolean, readFloat/writeFloat, etc.

Network Streams
Java allows you to access a le on the Internet as easily as youd access a le on your own computer. The class java.net.URL represents a network resource.
URL url = new URL("http://www.columbia.edu") ; InputStream in = url.openStream() ; int ch ; while( (ch = in.read()) != -1 ) { ... }

Exceptions
I/O provides many opportunities for unexpected errors. What if the user deletes a le while we are trying to read it? What if the network connection goes dead while we try to connect to a URL? We call unexpected events in the life of a program exceptions. Java provides a mechanism for handling exceptions gracefully.

Exceptions: 2
If a method generates (throws) an exception, it must declare that exception in a throws clause. E.g., all of the InputStream methods throw IOException:
public abstract int read() throws IOException ;

If a method calls another method that may throw an exception, it must:

throw the exception itself (declare it in a throws clause), or handle (catch) the exception

The Execution Stack


When an exception is thrown, execution stops immediately and control is transferred to the calling method. If the exception is not caught, control is immediately transferred to the method that called that method. And so on. This chain of method calls is called the execution stack. This is what you see when an exception spills through to the terminal (e.g., a NullPointerException): a list of method names and line numbers detailing at what point the exception was thrown and how execution reached that point.

Catching Exceptions
Exceptions are handled using a try-catch block. Code that may throw an exception is put inside a try block, followed by catch clauses that match a particular exception.
try { InputStream inFile = new FileInputStream("a.txt") ; int ch = inFile.read() ; } catch( FileNotFoundException e ) { System.err.println("No file a.txt.") ; } catch( IOException e ) { System.err.println("Error reading a.txt") ; }

Exception Types
Exception is a subclass of Throwable. Particular exceptions subclass Exception to provide more descriptive error information. Exception has a method getMessage() that returns a description of the error encountered.
try { InputStream inFile = new FileInputStream("a.txt") ; } catch( FileNotFoundException e ) { System.err.println( e.getMessage() ) ; /* "a.txt (No such file or directory)" */ }

Exception Types: 2
When an exception is thrown, the rst assignment-compatible catch clause will match. That means that supertype clauses will handle subtype exceptions.
try { InputStream inFile = new FileInputStream("a.txt") ; int ch = inFile.read() ; } catch( Exception e ) { /* This clause catches everything. */ System.err.println("General error.") ; } catch( FileNotFoundException e ) { /* This clause will never execute. */ System.err.println("Specific error.") ; }

The finally Clause


A try-catch block can have a finally clause containing code to be executed whether or not an exception is thrown. A finally clause is typically used to close any open streams and clean up any internal state.
try { int ch = inStream.read() ; } catch( IOException e ) { System.err.println( e.getMessage() ) ; } finally { inStream.close() ; /* The stream gets closed whether or not * the read succeeds. */ }

Exceptions Inside Handlers


If an exception is thrown inside a catch or finally clause, it will not be handled inside the same try block; execution will halt and control will be sent to the next method up the stack.
InputStream inFile = null ; try { inFile = new FileInputStream("a.txt") ; } catch( FileNotFoundException e ) { inFile = new FileInputStream("a.txt") ; /* Calling method must handle * FileNotFoundException */ }

Unchecked Exceptions
You may be wondering why youve never been asked to catch a NullPointerException. NullPointerException is a subclass of RuntimeException, the parent class of all unchecked exceptions. Methods that throw unchecked exceptions are not required to be enclosed in a try-catch block. Other unchecked exceptions are:

Errors
Error is subclass of Throwable that encompasses runtime errors that are too serious to be caught. Some subclasses of Error that youve probably spent some time with:

Dening Exceptions
To create your own exception, extend Exception. An exception should provide a constructor that takes information about the nature of the error and passes it to Exception as a message.
public class ReallyBadException extends Exception { public ReallyBadException(int badness) { super("A really bad exception occured: " +badness+" out of 10") ; } }

NoClassDefFoundError NoSuchMethodError

ArrayIndexOutOfBoundsException ClassCastException ArithmeticException

Object Serialization
Weve talked about how to read and write character data and binary data of a primitive type. What if we want to do I/O on an object? The process of reading or writing an object to an I/O stream is called object serialization. The streams that read and write object data are ObjectInputStream and ObjectOutputStream. Objects are serialized and deserialized using the methods writeObject and readObject.

Object Serialization: 2

Serializable

Invoking writeObject causes all of the non-static elds of the object to be written to the stream. If a eld is of an object type, the eld itself will be serialized. The serialization process does not just operate on a single object: it operates on an entire set of objects that can be reached through the references starting with that object (a reference graph). Invoking readObject reconstitutes the reference graph and returns a reference to the root (i.e., the original object).

A class indicates it can be serialized by implementing the Serializable interface. The interface has no methodsit is a marker interface. Any object elds of the class should also be Serializable. If the class is a subclass, its parent must have a no-arg constructor or itself be Serializable.

import java.io.* ; public class Foo implements Serializable {

Object Versions

private int x, y ; public Foo(int x, int y) { this.x = x ; this.y = y ; } public static void main(String[] args) { try { Foo a = new Foo(3,7) ; ObjectOutputStream out = new ObjectOutputStream ( new FileOutputStream( "a.tmp" ) ) ; out.writeObject(a) ; } }

ObjectInputStream in = new ObjectInputStream ( new FileInputStream( "a.tmp" ) ) ; Foo b = (Foo) in.readObject() ; } catch( IOException e ) { System.err.println( e.getMessage() ) ; }

The serialization process assigns a version ID to every class. If we change anything about the class, the version ID will change. In order to deserialize a class, the version ID of the serialized version must exactly match that of the .class le. An attempt to deserialize a non-matching class will cause an InvalidClassException. To make supercially dissimilar versions of a class compatible with respect to serialization, we can dene the constant:
public static final long serialVersionUID

Transient Fields
Fields marked with the modier transient are not serialized. As the name indicates, they are usually values that arent part of the objects permanent state.
public class Circle implements Serializable { private double r ; private transient double area ; public Circle(double r) { this.r = r ; area = Math.PI * r * r ; } ... }

Customizing Serialization
If dumping all of the objects elds isnt what we want to do, we can dene the methods writeObject and readObject. private void writeObject( ObjectOutputStream out) throws IOException ; private void readObject( ObjectInputStream in) throws IOException ; A class that denes these methods takes responsibility for serializing its own elds.

You might also like