(syllabus and calendar)

Ch. 10. Using I/0
pp. 365-106

../week10.zip

Session 10


quiz


If there is time remaining, we can look at extras

I/O - (input/ouput) overview

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.

The out field

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.

The in field

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.

  


binary data and unicode characters

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.

Abstract class java.io.Writer

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.


Byte array and System.in.read()

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.


File I/O with FileInputStream

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.


Console class

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


FileInputStream and FileOutputStream

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


Compare two files

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


FileReader and BufferedReader

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.
http://download.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#BufferedReader%28java.io.Reader,%20int%29

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 ready() method

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


Buffered reader and System.in

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.


Getting a numeral from the keyboard

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:



FileWriter and write()

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


Copying a File to Another File: Stream versus Channel

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.


Quiz: Session 10

  1. Java's build-in stream for output  ____________.__________ is in the package java.________, and we used it in Week 1, "HelloWorld.java".

  2. System.out.println() and System.out.print()write to standard output. What is the equivalent for reading from standard input?

  3. java.io.Writer is an abstract class that is extended by java.io.BufferedWriter and java.io.FileWriter. Why should java.io.Writer be an abstract class instead of an interface?

  4. What does read() return at the end of the file?

  5. What does flush() do?

  6. What is the fully-qualified name of the Exception most general to the io package?

  7. java.io.BufferedReader and java.io.Console have a method that allows you to read an entire line of text from the keyboard, which is more efficient than reading each character one-by-one. The name of this method is: ________________

  8. The following code
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
    converts keyboard bytes into a non-buffered_____________ and finally into a buffered _____________

  9. Is it possible to compare two files, character-by-character, by using a non-buffered FileInputStream? (See FileComparison.java)

  10. Can write(byte[] b, int offset, int lenOfByteArray) on a FileOutputStream be used to write out an entire file? (See CopyFileWithStream.java)

=====================

  1. Java's build-in stream for output System.out is in the package java.io, and we used it in Week 1, "HelloWorld".
  2. System.out.println() and System.out.print()write to standard output. What is the equivalent for reading from standard input?
    System.in.read()
  3. java.io.Writer is an abstract class that is extended by java.io.BufferedWriter and java.io.FileWriter. Why should java.io.Writer be an abstract class instead of an interface?
    To provide some default functionality, such as methods for append, close, flush, write, while allowing subclasses to have specialization for close, flush, and write. Closing a file might be different than closing a buffer.
  4. What does read() return at the end of the file?
    If no byte is available because the end of the stream has been reached, the value -1 is returned.
  5. What does flush() do?
    The flush method causes whatever is in the buffer to be written out, and, for efficiency is typically used to cause the buffer to be written out when full. It is also used to write out whatever is in the buffer at the very end, whether the buffer is full or not.
  6. What is the fully-qualified name of the Exception most general to the io package?
    IOException.
  7. java.io.BufferedReader and java.io.Console have a method that allows you to read an entire line of text from the keyboard, which is more efficient than reading each character one-by-one. The name of this method is: readline. For details, see http://download.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#readLine%28%29
  8. The following code
     BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
    converts keyboard bytes into a non-buffered stream and finally into a buffered stream.
  9. Is it possible to compare two files, character-by-character, by using a non-buffered FileInputStream? (See FileComparison.java)
    Yes.
  10. Can write(byte[] b, int offset, int lenOfByteArray) on a FileOutputStream be used to write out an entire file? (See CopyFileWithStream.java)
    Yes.