Monday 13 March 2017

I/O Basics & Reading Console Input - Java Tutorials

I/O Basics

As you may have noticed while reading the preceding 11 chapters, not much use has been made of I/O in the example programs. In fact, aside from print( ) and println( ), none of the I/O methods have been used significantly. The reason is simple: most real applications of Java are not text-based, console programs. Rather, they are graphically oriented applets that rely upon Java’s Abstract Window Toolkit (AWT) for interaction with the user. Although text-based programs are excellent as teaching examples, they do not constitute an important use for Java in the real world. Also, Java’s support for console I/O is limited and somewhat awkward to use—even in simple example programs. Text-based console I/O is just not very important to Java programming.

The preceding paragraph notwithstanding, Java does provide strong, flexible support for I/O as it relates to files and networks. Java’s I/O system is cohesive and consistent. In fact, once you understand its fundamentals, the rest of the I/O system is easy to master.


Streams

Java programs perform I/O through streams. A stream is an abstraction that either produces or consumes information. A stream is linked to a physical device by the Java I/O system. All streams behave in the same manner, even if the actual physical devices to which they are linked differ. Thus, the same I/O classes and methods can be applied to any type of device. This means that an input stream can abstract many different kinds of input: from a disk file, a keyboard, or a network socket. Likewise, an output stream may refer to the console, a disk file, or a network connection. Streams are a clean way to deal with input/output without having every part of your code understand the difference between a keyboard and a network, for example. Java implements streams within class hierarchies defined in the java.io package.

If you are familiar with C/C++/C#, then you are already familiar with the concept of the stream. Java’s approach to streams is loosely the same.


Byte Streams and Character Streams

Java 2 defines two types of streams: byte and character. Byte streams provide a convenient means for handling input and output of bytes. Byte streams are used, for example, when reading or writing binary data. Character streams provide a convenient means for handling input and output of characters. They use Unicode and, therefore, can be internationalized. Also, in some cases, character streams are more efficient than byte streams.

The original version of Java (Java 1.0) did not include character streams and, thus, all I/O was byte-oriented. Character streams were added by Java 1.1, and certain byte-oriented classes and methods were deprecated. This is why older code that doesn’t use character streams should be updated to take advantage of them, where appropriate.

One other point: at the lowest level, all I/O is still byte-oriented. The character-based streams simply provide a convenient and efficient means for handling characters.

An overview of both byte-oriented streams and character-oriented streams is presented in the following sections.


The Byte Stream Classes

Byte streams are defined by using two class hierarchies. At the top are two abstract classes: InputStream and OutputStream. Each of these abstract classes has several concrete subclasses, that handle the differences between various devices, such as disk files, network connections, and even memory buffers. The byte stream classes are shown in Table 12-1. A few of these classes are discussed later in this section. Others are described in Part II. Remember, to use the stream classes, you must import java.io.

The abstract classes InputStream and OutputStream define several key methods that the other stream classes implement. Two of the most important are read( ) and write( ), which, respectively, read and write bytes of data. Both methods are declared as abstract inside InputStream and OutputStream. They are overridden by derived stream classes.


The Character Stream Classes

Character streams are defined by using two class hierarchies. At the top are two abstract classes, Reader and Writer. These abstract classes handle Unicode character streams. Java has several concrete subclasses of each of these. The character stream classes are shown in Table 12-2.

The abstract classes Reader and Writer define several key methods that the other stream classes implement. Two of the most important methods are read( ) and write( ), which read and write characters of data, respectively. These methods are overridden by derived stream classes.


The Byte Stream Classes

Stream Class                               Meaning

BufferedInputStream                    Buffered input stream

BufferedOutputStream                 Buffered output stream

ByteArrayInputStream                 Input stream that reads from a byte array

ByteArrayOutputStream              Output stream that writes to a byte array

DataInputStream                          An input stream that contains methods for reading the 
                                                     Java standard data types

DataOutputStream                       An output stream that contains methods for writing the 
                                                     Java standard data types

FileInputStream                           Input stream that reads from a file

FileOutputStream                        Output stream that writes to a file

FilterInputStream                         Implements InputStream

FilterOutputStream                      Implements OutputStream

InputStream                                  Abstract class that describes stream input

OutputStream                               Abstract class that describes stream output

PipedInputStream                        Input pipe

PipedOutputStream                     Output pipe

PrintStream                                 Output stream that contains print( ) and println( )

PushbackInputStream                  Input stream that supports one-byte “unget,” which returns a byte 
                                                     to the input stream

RandomAccessFile                      Supports random access file I/O

SequenceInputStream                  Input stream that is a combination of two or more input streams 
                                                     that will be read sequentially, one after the other


The Character Stream I/O Classes

Stream Class                              Meaning

BufferedReader                           Buffered input character stream

BufferedWriter                            Buffered output character stream

CharArrayReader                        Input stream that reads from a character array

CharArrayWriter                         Output stream that writes to a character array

FileReader                                   Input stream that reads from a file

FileWriter                                    Output stream that writes to a file

FilterReader                                 Filtered reader

FilterWriter                                  Filtered writer

InputStreamReader                      Input stream that translates bytes to characters

LineNumberReader                     Input stream that counts lines

OutputStreamWriter                    Output stream that translates characters to bytes

PipedReader                                 Input pipe

PipedWriter                                  Output pipe

PrintWriter                                    Output stream that contains print( ) and println( )

PushbackReader                           Input stream that allows characters to be returned to the 
                                                      input stream

Reader                                          Abstract class that describes character stream input

StringReader                                Input stream that reads from a string

StringWriter                                 Output stream that writes to a string

Writer                                           Abstract class that describes character stream output


The Predefined Streams

As you know, all Java programs automatically import the java.lang package. This package defines a class called System, which encapsulates several aspects of the run-time environment. For example, using some of its methods, you can obtain the current time and the settings of various properties associated with the system. System also contains three predefined stream variables, in, out, and err. These fields are declared as public and static within System. This means that they can be used by any other part of your program and without reference to a specific System object.

System.out refers to the standard output stream. By default, this is the console. System.in refers to standard input, which is the keyboard by default. System.err refers to the standard error stream, which also is the console by default. However, these streams may be redirected to any compatible I/O device.

System.in is an object of type InputStream; System.out and System.err are objects of type PrintStream. These are byte streams, even though they typically are used to read and write characters from and to the console. As you will see, you can wrap these within character-based streams, if desired.

The preceding chapters have been using System.out in their examples. You can use System.err in much the same way. As explained in the next section, use of System.in is a little more complicated.





Reading Console Input

In Java 1.0, the only way to perform console input was to use a byte stream, and older code that uses this approach persists. Today, using a byte stream to read console input is still technically possible, but doing so may require the use of a deprecated method, and this approach is not recommended. The preferred method of reading console input for Java 2 is to use a character-oriented stream, which makes your program easier to internationalize and maintain.

Java does not have a generalized console input method that parallels the standard C function scanf( ) or C++ input operators.

In Java, console input is accomplished by reading from System.in. To obtain a character-based stream that is attached to the console, you wrap System.in in a BufferedReader object, to create a character stream. BuffereredReader supports a buffered input stream. Its most commonly used constructor is shown here:

      BufferedReader(Reader inputReader)

Here, inputReader is the stream that is linked to the instance of BufferedReader that is being created. Reader is an abstract class. One of its concrete subclasses is InputStreamReader, which converts bytes to characters. To obtain an InputStreamReader object that is linked to System.in, use the following constructor:

      InputStreamReader(InputStream inputStream)

Because System.in refers to an object of type InputStream, it can be used for inputStream. Putting it all together, the following line of code creates a BufferedReader that is connected to the keyboard:

  BufferedReader br = new BufferedReader(new
                          InputStreamReader(System.in));

After this statement executes, br is a character-based stream that is linked to the console through System.in.


Reading Characters

To read a character from a BufferedReader, use read( ). The version of read( ) that we
will be using is

      int read( ) throws IOException

Each time that read( ) is called, it reads a character from the input stream and returns it as an integer value. It returns –1 when the end of the stream is encountered. As you can see, it can throw an IOException.

The following program demonstrates read( ) by reading characters from the console until the user types a “q”:

  // Use a BufferedReader to read characters from the console.
  import java.io.*;

  class BRRead {
    public static void main(String args[])
      throws IOException
    {
      char c;
      BufferedReader br = new
              BufferedReader(new InputStreamReader(System.in));
      System.out.println("Enter characters, 'q' to quit.");

      // read characters
      do {
        c = (char) br.read();
        System.out.println(c);
      } while(c != 'q');
    }
  }

Here is a sample run:

  Enter characters, 'q' to quit.
  123abcq
  1
  2
  3
  a
  b
  c
  q

This output may look a little different from what you expected, because System.in is line buffered, by default. This means that no input is actually passed to the program until you press ENTER. As you can guess, this does not make read( ) particularly valuable for interactive, console input.


Reading Strings

To read a string from the keyboard, use the version of readLine( ) that is a member of the BufferedReader class. Its general form is shown here:

      String readLine( ) throws IOException

As you can see, it returns a String object. The following program demonstrates BufferedReader and the readLine( ) method; the program reads and displays lines of text until you enter the word “stop”:

  // Read a string from console using a BufferedReader.
  import java.io.*;

  class BRReadLines {
    public static void main(String args[])
      throws IOException
    {
      // create a BufferedReader using System.in
      BufferedReader br = new BufferedReader(new
                              InputStreamReader(System.in));
      String str;

      System.out.println("Enter lines of text.");
      System.out.println("Enter 'stop' to quit.");
      do {
        str = br.readLine();
        System.out.println(str);
      } while(!str.equals("stop"));
    }
  }

The next example 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 BufferedReader to read from the console.

  // 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]);
      }
    }
  }

Here is a sample run:

  Enter lines of text.
  Enter 'stop' to quit.
  This is line one.
  This is line two.
  Java makes working with strings easy.
  Just create String objects.
  stop
  Here is your file:
  This is line one.
  This is line two.
  Java makes working with strings easy.
  Just create String objects.

No comments:

Post a Comment