Input

The classes to do input are mostly the flip side of the output classes we have already seen. Java programs access external data by instantiating a stream on the data source. Each place from which an input stream can flow has a class dedicated to getting that kind of input. Input is read from a stream of data representing the file, pipe, socket, memory array, or whatever. If you want to read 16-bit characters, you use a Reader class. If you want to read binary bytes or ASCII, you use an input stream.

Inputting double-byte characters

As usual, first decide between binary and character I/O, then choose your class based on where the data is coming from. For reading double-byte character data, you will use one of the Reader classes shown in Table 17-6. Note the symmetry with the Writer classes.

Table 17-6. Choose the Reader class based on where the Input comes from

image

There are only four places from which you can read chars with a Reader, and FileReader is by far the most common. That class opens a connection to a file.The constructors are shown in Table 17-6. The constructor takes an argument that is the String pathname to the file, or a File object or FileDescriptor object.

Basic Reader methods

All Readers give you at least these three somewhat basic input methods:

public int read()
public int read(char[] cbuf)
public int read(char[] cbuf, int from, int len)

These read into, respectively, a single character, an array of characters, and a range in an array of characters. The call will not return until some data is available to read, although it won't necessarily fill the array. The return value will be -1 if the Reader hits end of file (EOF). This is why the single char call returns a 32-bit int, even though it only reads a 16-bit character. The high-order 16 bits in the return value allow you to distinguish EOF from a character read. Those bits will be zero when a character is read, and 0xFFFF when EOF is reached. Test the return value for equality with -1 to see if you reached EOF.

An input problem rears its ugly head

At this point, from general symmetry, you are probably expecting to “wrap” another class on top of these Readers. That class will probably be called PrintReader, and it will have all the convenient methods for reading a String and returning a short, an int, a float, a boolean, etc. Bzzzt!

Sorry, the design falls apart here. There is no such class as PrintReader. Not only that, there is no class that can give you the desired feature of being able to read back in exactly the same number values as were output using PrintWriter. The problem is an algorithmic one. Numbers in printed format vary in length, so your code has no way of telling where one number ends and an immediately adjacent starts. For example, if you use PrintWriter to print two ints like this into a file (with no space between them):

myPW.print(293);
myPW.print(19);

The file will contain the string “29319”, but if you try to read those numbers back in from that file, because of the variable length, there is no way of telling where one int ends and the next one starts. No program in any language can deduce whether the ints were originally 2 and 9319, or 29 and 319, or 293 and 19, or 2931 and 9. This problem does not arise with binary output, because all the binary types (short, int, float, etc.) have a fixed known size. This “where does a string of digits end?” problem is the reason that the XML language (see Chapter 27) always marks the end of a field with a closing tag.

The best you can do when reading printed numbers is to read characters until you hit something that can't be part of a number (e.g., a space), then assemble a number out of the characters that preceded it. It's common to break up such files with end-of-line sequences, and it's convenient to be able to read a line at a time and tokenize (bundle together the groups of) the characters on that line.

This is exactly what the Scanner class does. Scanners make Java input a pleasure! See the following code example.

import java.io.*;
import java.util.Scanner;
import static java.lang.System.*;
public class Example5 {

       public static void main(String args[]) {
                FileReader myFR = null;
                try {
                  myFR = new FileReader( "Example5.java" );

                  Scanner sc = Scanner.create(new BufferedReader(myFR));
                  while(sc.hasNext())
                         out.println( sc.next() );
                } catch(IOException x) { err.println("Excp: " +x); }
       }
}

Another approach is to write all numeric strings into fixed length fields that are, say, 20 characters long. Then you can always read in fixed-length input. Another approach is to avoid reading/writing printable data; instead, do it all with binary byte streams. Another suggestion is to make your data totally portable and unambiguous by using XML. I'll be very glad when all word processors switch to saving in XML format. Have you ever had the experience of having a very old data file, but no longer have the application to read it? That data loss won't happen when all our data is in XML format.

Input is messier than output.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.175.253