Streams are ordered sequences of data that have
a source (inpute streams) or
destination (output streams).
The package java.io has two major parts:
I/O is either text-based or data-based.
Text-based I/O works with streams of human-readable chracters, while data-based I/O works with streams of binary data.
The byte streams are called
input streams and output streams.
The character streams are called
readers and writers.
 
All these cases make up the IO 'zoo'. It contains many animals, some quite exotic.
In addition in java.util there are classes for handling ZIP files.
For nearly every input stream there is a corresponding output stream,
and for most input or output streams there is a corresponding reader or
writer character stream of similar functioinality, and vice versa.
This `rule of thumb' can help you to orient in the variety of IO classes.
Examples are InputStream, OutputStream - abstract classes that declare methods to read bytes from a particular source (to write bytes to a particular destination), FileReader, FileWriter - character streams that operate with files, etc
If you reference a disk file with a RandomAccessFile reference instead of a File reference, you can use seek() to move to a desired point in the file and then access it from there. The method seek() counts in bytes and the count is from zero, just like an array index.
For details, see the Java documentation on RandomAccessFile.
(Not on the cps530 course).
In between there can be other objects which may filter the stream, buffer it, or divide it into structured chunks.
The producer object can be a file, but it could also be the keyboard, an Internet connection, or anything which produces a flow of data.
The consumer might be a Java AWT component such as a TextArea, or another file, or an Internet connection or an object representing a printer.
Java 1.1 and later has two kinds of streams. Byte streams are flows of (binary) data. Character streams are flows of 16 bit Unicode characters.
Character streams did not exist in Java 1.0. They were added for the purposes of internationalization. (As long as only ascii characters were used, one byte was enough to encode them so the streams for characters and bytes could be the same.)
Coverage of all the child streams is beyond the scope of this course. Here are names of only a few classes:
Only a few of the child classes need to be mentioned. These are BufferedReader, PrintWriter, OutputStreamWriter, InputStreamReader, FileReader, FileWriter. The latter two classes are actually used to convert from byte streams to character streams.
For convenience, there
still exists the PrintStream
class, deprecated
from Java 1.1 which will print bytes as characters. This is useful for
compatibility with stdout.
There can be several forms with different arguments. All return ints. Note that InputStream, OutputStream, Reader and Writer are all abstract as are the read() and write() methods which belong to them. This means that subclasses are responsible for implementing these methods. Not all the subclasses do so.
The many subclasses of these classes add more functionality by reading and writing more structured data such as lines of text or floating point numbers.
InputStream Reader int read(); int read(byte [] b)
int read(byte [] b, int offset, int length)
int read() int read(char[] c)
int read(char[] c, int offset, int length)
OutputSream Writer write(int b) write(int [] b)
write(int [] b, int offset, int length)
write(int c) write(char [] c)
write(char [] c, int offset, int length)
write(String s)
write(String s, int offset, int length)
All these throw IOExceptions.
Question: can "read" block, and if yes, when?
Answer: - ?
Question: Why "read()" from InputStream has the return type "int"?
It is supposed to read bytes, not integers.
Answer: - ?
But there is one key idea you need to know about: how to combine streams.
It is especially important to know how to combine the source/destination type streams with the processing type streams.
You do this by linking them together or wrapping the processing streams around the source/destination streams. (The process is not unlike wrapping primitive data types with the corresponding Java classes. With streams thought there can be multiple layers.)
Similarly, the write() method in a writable filter stream filters the data and then writes it to the underlying stream.
The processing done by the streams depends on the stream. Some streams buffer the data, some count data as it goes by, and others convert data to another form.
In the following example we attach a filter stream to the standard input stream when we create the filter stream:
BufferedReader d = new BufferedReader(new DataInputStream(System.in)); String input; while ((input = d.readLine()) != null) { ... //do something interesting here }The readLine method has been deprecated in the DataInputStream; therefore it is wrapped in a BufferedReader.
Using the Reader and Writer classes and their subclasses is similar:
The following program demonstrates BufferedReader class and the readLine() method. The program creates a tiny text editor. It creates an array of String objects and then reads in lines of text, storing each line in the array. It will read up to 100 lines or until you enter "stop". It uses a buffer to read from the console.
// From H.Schildt & P.Naughton "Java 2: The complete reference". // A tiny editor. import java.io.*; class TinyEdit { public static void main(String args[]) throws IOException { // create a BufferedReader using System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str[] = new String[100]; System.out.println("Enter lines of text."); System.out.println("Enter 'stop' to quit."); for(int i=0; i<100; i++) { str[i] = br.readLine(); if(str[i].equals("stop")) break; } System.out.println("\nHere is your file:"); // display the lines for(int i=0; i<100; i++) { if(str[i].equals("stop")) break; System.out.println(str[i]); } } }Without buffering, each invocation of read() or readLine() could cause bytes to be read from the file, converted into characters, and then returned, which can be very inefficient.
For example, streams from the Internet produced by various java.net classes are usually byte streams. Here is a simple example (later we consider the URL class; it is in java.net).
For real-world programs, the recommended method of writing to the console is through a PrintWriter stream. It is one of the character-based streams.
This class provides methods that print formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams. This class has 4 constructors:
PrintWriter(OutputStream out) Create a new PrintWriter, without automatic line flushing, from an existing OutputStream. PrintWriter(OutputStream out, boolean flushOnNewline) Create a new PrintWriter from an existing OutputStream. PrintWriter(Writer out) Create a new PrintWriter, without automatic line flushing. PrintWriter(Writer out, boolean autoFlush) Create a new PrintWriter.In the second constructor, flushOnNewline controls whether Java flushes the output stream every time a newline character ('\n') is output. If it is true, then flushing automatically takes place.
PrintWriter supports the print() and println() methods for all types including Object.
To write to the console by using a PrintWriter, specify System.out for the output stream and flush the stream after each newline.
The following application illustrates using a PrintWriter to handle console output:
// Demonstrate PrintWriter import java.io.*; public class PrintWriterDemo { public static void main(String args[]) { PrintWriter pw = new PrintWriter(System.out, true); pw.println("This is a string"); int i = -7; pw.println(i); double d = 4.5e-7; pw.println(d); } }
Both reading and writing is usually buffered by default.
Here is an example
of problems with the input buffer. There can also be problems with the
output buffer. Sometimes you need to explicitly flush it.
/** * BufferStuff.java * Reads lines of text from the keyboard and saves it to a file named * by a command line argument. * * Illustrates buffer problems. Both the input and the output are buffered. * This is for efficiency reasons but can cause programming problems. * Note the comments below and the use of skip(), available() and the "true" * argument in the PrintWriter constructor. int available() Returns the number of bytes that can be read from this file input stream without blocking. long skip(long n) Skips over and discards n bytes of data from the input stream. * * DG Nov. 99 */ import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStreamReader; import java.io.FileWriter; import java.io.File; import java.io.IOException; public class BufferStuff { public static void main(String [] args) { BufferedReader br = null; PrintWriter pw = null; File f = null; String line = null; if(args.length != 1) { System.out.println("USAGE: java BufferStuff <filename>"); System.exit(0);
} f = new File(args[0]); if(f.exists()) { System.out.println("File Exists. Overwrite? (y/n)"); try { switch(System.in.read()) { // There is a buffer here. Try removing the skip() // Then, if the user types 'y' an empty string is still // there (!) which will cause an immediate exit of the // while loop below. On the other hand, if the user types // "yes" (still without the skip(), the 'y' will be consumed // and the "es" written to the file! case 'y': System.in.skip(System.in.available())
break; default: System.exit(0); } } catch (IOException e) {} } try { //"true" here flushes the output buffer after every pw.println(). // You could instead call pw.flush() after each pw.println(). // (Actually, this is not needed in this particular program.) pw = new PrintWriter(new FileWriter(f), true); br = new BufferedReader(new InputStreamReader(System.in)); do { System.out.println("Enter a line. To stop, press <enter>"); line = br.readLine(); pw.println(line); } while(!line.equals("")); br.close(); pw.close(); } catch(IOException ioe) { ioe.printStackTrace(); } } }
This program works correctly.
Now, suppose you removed the skip() method.
BufferStuff1a.java -BUGGED.
In this case, strange things may happen.
MORAL: Never forget to flush.
Illustrates a number of Java's IO classes.
Object Serialization from the on-line tutorial.