(syllabus and calendar)Ch. 10. Using I/0 |
Session 10
If there is time remaining, we can look at extras |
When we first learned how to read, we started with our 'A', 'B', 'C's, the name of individual letters of the alphabet (bytes, chars). Soon, we read individual words isolation, then sentences containing multiple words, then paragraphs, then entire articles in the Sports section. To read an entire article, we still have to deal with its paragraphs. Consider a newspaper article to be a file, and a paragraph to the chunk of paragraph text we absorb as a page (or screen). Our minds can hold a paragraph of information in short-term memory, which we might consider to be a buffer. Just as we process a two-page article paragraph by paragraph, so Java processes a file by using a buffer.
It is more efficient to reduce input/output operations by grouping the individual elements together for processing. Another analogy might be using a big spoon to eat a set of corn flakes, instead of individual flake by flake, which would be a lot of input operations. Note that many people prefer eating potato chips one-by-one (the fun of "finger-food"), instead of crushing them into a big spoon. Potato chips are IO-intensive.

Cattle are efficient in their input and and productive in their output, as a hike on many trails makes evident. Cows prefer to chomp on entire large mouthfuls of grass rather than pick at individual blades of grass (or individual potato chips). Similarly, dogs are IO-efficient, filling the entire buffer of their maul at once, unlike cats nibble in an IO-intensive manner.
Another way to process food is with a stream. IO-efficient folks slurp up long spaghetti instead of cutting each individual spaghetto. Some call it uncouth, others call it IO-efficient.

A straw is an IO-efficient way to stream the contents of a beverage into a mouthful (a buffer).


The Java reader for an input stream converts bytes to characters. http://download.oracle.com/javase/6/docs/api/java/io/InputStreamReader.html
InputStreamReader isr = new InputStreamReader(System.in);
The input stream reader is "wrapped" in a buffered reader for efficiency, that is, the reduction of input/output operations:
BufferedReader buffer = new BufferedReader(isr);
or, the shorter version:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
Think of the straw as System.in, the fluid moving throw the straw as an input stream, and the throat receiving a buffered mouthful/gulp.
An input stream is like an input straw, and a buffered reader is like a big gulp that only occurs from time to time.

The input and output facilities of Java include:
The abstract class, java.io.InputStream http://java.sun.com/javase/6/docs/api/java/io/InputStream.html provides implementation methods for managing the bytes in an stream, such as read(byte[] b), mark(int readlimit), reset(), skip(long n), and close(). Therefore, subclasses, such as AudioInputStream and FileInputStream have the choice to reuse the implementation or overwrite it.

A bit like System.out.println(), the outfielder in baseball outputs something visible.
The java.io package ( http://java.sun.com/javase/6/docs/api/java/io/package-summary.html ) "Provides for system input and output through data streams, serialization and the file system". The default package, java.lang, provides the most basic I/O functionality. For example, the System class ( http://java.sun.com/javase/6/docs/api/java/lang/System.html ) has a static field, out, the "standard output stream", that enables us to call System.out.println().
However, this output stream derives from the io package, which includes the PrintStream class ( http://java.sun.com/javase/6/docs/api/java/io/PrintStream.html ) with the out field. This field has the println() method that supports sending a stream of bytes to a device (such as the console) or a file. Java follows UNIX insofar as standard error, the static err field, is the same device as standard out, and so error reporting automatically takes advantage of the print stream.
Similarly, we get System.in.read() to read
from the console from java.io.InputStream - the
http://java.sun.com/javase/6/docs/api/java/io/InputStream.html. So the
standard input, output, and error streams of java.io
are made available to java.io.System. Standard
input is given by System.in -
http://download.oracle.com/javase/6/docs/api/java/lang/System.html#in. We
can think of a baseball pitcher as an in-fielder who reads signals from the
catcher.

To work with low-level binary data, use a byte stream.
At a higher level, to work with unicode characters, use a character stream. (This is similar to the file-transfer-protocol (ftp) toggle, binary, which sets the transfer operation to work with bytes instead of characters.)
A char is a convenient way to work with what the system considers to be a byte, and that's why we can convert char to byte and byte to char. Similarly, a character stream is a convenience built on top of a byte stream.
The class java.io.Writer ( http://java.sun.com/javase/6/docs/api/java/io/Writer.html ) is abstract to provide both some functionality and some customizability. This class
For example, within the Java APIs, a BufferedWriter, a StringWriter, and a PrintWriter might use different offsets, ways to flush, and close.
If you want to handle ALL the possible I/O exceptions, catch java.io.IOException, ( http://java.sun.com/javase/6/docs/api/java/io/IOException.html ), a direct subclass of java.lang.Exception. This subclass is the superclass of many specialized exceptions, such as java.io.FileNotFoundException.

Because IOException is not a subclass of RuntimeException, the compiler checks to see that IO exceptions are handled or the method declares it throws the exception. The architects of Java thereby encourage us to be proactive in handling possible IO problems.
To read bytes from the console, use a byte array. The byte array can deal with characters.

Note that the byte array is of a fixed size, but this is fine for many use cases, such as reading in a credit card number, which can later be parsed as integers. A common way to work with user input is with a buffered reader. This program parses the user input to extract a numeric value.

When we work with arrays, we have the limitation of needing to know the size of the array necessary to store the data. To read in an entire file (and not have to know its size beforehand), read in until the end-of-file (EOF) marker, negative 1 (-1). The read method of java.io.inputStream returns -1 when there is nothing more to read in the file.
Because the read method is on an instance of type FileInputStream, line 14 calls the constructor for a file input stream. This class is a subclass of the more general InputStream, which also has a read method. Lines 21-16 define a catch block that provides more guidance to the user than the default exception handling of the JVM.

Use the Console class so end-users can keep
their password hidden from people near their computer screen.
http://download.oracle.com/javase/6/docs/api/java/io/Console.html
We do have to construct the Console. Instead,
we call the static console method of the
System class, which is
final.
http://download.oracle.com/javase/6/docs/api/java/lang/System.html#console%28%29
The program compares the two passwords on Line 28. Each password is stored in an array of bytes, and a static method of java.util.Arrays performs the comparison - http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#equals%28char[],%20char[]%29



A common use for file IO is to update text, such as a name. Here, we use a file input stream to demonstrate substitution. Line 76 replaces each blank space with a hyphen and saves this to the destination file. To run this program, type java Hypen mySourceFile myDestinationFile


We can compare two files, byte-by-byte, using the read method on a file input stream. See Lines 48-49, which call this method: http://download.oracle.com/javase/6/docs/api/java/io/FileInputStream.html#read%28%29


If I run: java FileComparison myLetters.txt
myLetters2.txt
The output is: original says: g but second file says: z
Here the input stream is well matched to the input buffer.

Here, the buffer is too small for efficient input:

A small buffer can still work, but it takes patience and persistence:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
Think of the straw as System.in, the fluid moving throw the straw as an input stream, and the throat receiving a buffered mouthful/gulp. (An input stream is almost an input straw.)
If you know that the file to input or output is not binary but contains characters, use an instance of FileReader, which works with Unicode and supports all the major human languages, including Chinese, Japanese, and Arabic. A FileReader is a subclass of InputStreamReader ( http://java.sun.com/javase/6/docs/api/java/io/InputStreamReader.html ), which works with characters instead of bytes. The FileReader can be constructed from a file name (see Line 7 in the example below).
In the example below, line 8 wraps the FileReader inside a BufferedReader which holds a significant amounts of bytes, typically 1024 bytes (1 kilobyte), in a single buffer. The size of the buffer matters in some circumstances. For example, a small device, such as a cell phone screen, might need a smaller buffer than, say, a powerful server running servlets that processes large amounts of data rapidly. Java provides two constructor signatures for a buffered reader, one of which allows us to set a custom size:
BufferedReader
(Reader in)Creates a buffering character-input stream that uses a default-sized input buffer. http://download.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#BufferedReader%28java.io.Reader%29
BufferedReader
(Reader in, int sz)Creates a buffering character-input stream that uses an input buffer of the
specified size.
Typically, a servler running servlets has a buffer of 8 kilobytes, but some use 16 kilobytes - http://java.sun.com/developer/technicalArticles/Servlets/servletapi/ - but note that the Servlet API is part of the Enterprise Edition, not the Standard Edition.
The new IO package of the fourth version of Java, java.nio, added new classes for buffering - http://download.oracle.com/javase/6/docs/api/java/nio/package-summary.html. For example, java.nio provides a class for each primitive types (except boolean), and these are subclasses of Buffer - http://download.oracle.com/javase/6/docs/api/java/nio/Buffer.html
Buffering provides efficiency because we can read in, say, 4000 unicode (2 bytes each) characters instead of 80 characters. Without buffering, each invocation of read() or readLine() could fetch at most one line of characters. Assuming you want more than one or two characters, a buffered reader is useful for reading characters from the console or a file. (Reducing network roundtrips is useful because network latency can easily exceed JVM processing time. The throughput might be 5000% greater.)

This version includes try, catch, and finally blocks.

This verion has more robust exception handling and also indicates which classes its uses from the io.package instead of importing *.*

The java.io.Reader class provides a ready() method
http://download.oracle.com/javase/6/docs/api/java/io/Reader.html#ready%28%29
which subclasses override to take advantage of additional functionality:
http://download.oracle.com/javase/6/docs/api/java/io/InputStreamReader.html#ready%28%29
Note that the InputStream class does not have a ready() method and is not a
superclass of an InputStreamReader:
http://download.oracle.com/javase/6/docs/api/java/io/InputStream.html
Use input and output to echo input as output to screen:

Allow the input-output cycle to shut itself off when the user says to stop.

This example uses the constructor of java.lang.Character in Line 12 to get a single character object, then a string, then test whether the string representation of the character itself a representation of an integer. The parseInt method accepts a String as input, and outputs the corresponding integer value. The Character class is an object wrapper for a primitive char - http://download.oracle.com/javase/6/docs/api/java/lang/Character.html

A more sophisticated use of a buffered reader with integer parsing:

You can also write a Unicode file from the lines the user types at the console by creating an instance of java.io.FileWriter (Line 17) and calling the signature of the write method that takes a String as input (Line 33) - http://download.oracle.com/javase/6/docs/api/java/io/Writer.html#write%28java.lang.String%29

Two ways to copy a file are using streams and using channels. Streams are part of the standard io package. This program uses the java.io.FileOutputStream.write method (http://download.oracle.com/javase/6/docs/api/java/io/FileOutputStream.html#write%28byte[],%20int,%20int%29) to output a buffer of 1024 bytes to the FileOutputStream until there are not more bytes to write. The JVM knows there are no more bytes when the file input stream returns -1.
What user error might be expect to see in relation to line 27? What is the usage requirement to run the program successfully?

Channels are part of the the java.nio (new I/O) package - http://download.oracle.com/javase/6/docs/api/. Channels were added for:
If you work with databases, this advanced topic might be valuable with large tables. Classes in this package can also take advantage of a memory mapped file outside the JVM, which means the operating system directly uses hard disk space for paging a large file as if it were loaded into RAM.

=====================
-1 is
returned.