Friday 24 March 2017

The Character Streams - Java Tutorials

While the byte stream classes provide sufficient functionality to handle any type of I/O operation, they cannot work directly with Unicode characters. Since one of the main purposes of Java is to support the “write once, run anywhere” philosophy, it was necessary to include direct I/O support for characters. In this section, several of the character I/O classes are discussed. As explained earlier, at the top of the character stream hierarchies are the Reader and Writer abstract classes. We will begin with them.

As discussed in Chapter 12, the character I/O classes were added by the 1.1 release of Java. Because of this, you may still find legacy code that uses byte streams where character streams should be. When working on such code, it is a good idea to update it.


FileReader

The FileReader class creates a Reader that you can use to read the contents of a file. Its two most commonly used constructors are shown here:

      FileReader(String filePath)
      FileReader(File fileObj)


The Methods Defined by Reader

abstract void close( ):  Closes the input source. Further read attempts will generate an IOException.

void mark(int numChars):  Places a mark at the current point in the input stream that will remain valid until numChars characters are read.

boolean markSupported( ):  Returns true if mark( )/reset( ) are supported on this stream.

int read( ):  Returns an integer representation of the next available character from the invoking input stream. –1 is returned when the end of the file is encountered.

int read(char buffer[ ]):  Attempts to read up to buffer.length characters into buffer and returns the actual number of characters that were successfully read. –1 is returned when the end of the file is encountered.

abstract int read(char buffer[ ], int offset, int numChars):  Attempts to read up to numChars characters into buffer starting at buffer[offset], returning the number of characters successfully read. –1 is returned when the end of the file is encountered.

boolean ready( ):  Returns true if the next input request will not wait. Otherwise, it returns false.

void reset( ):  Resets the input pointer to the previously set mark.

long skip(long numChars):  Skips over numChars characters of input, returning the number of characters actually skipped.


Either can throw a FileNotFoundException. Here, filePath is the full path name of a file, and fileObj is a File object that describes the file.


The Methods Defined by Writer

abstract void close( ):  Closes the output stream. Further write attempts will generate an IOException.

abstract void flush( ):  Finalizes the output state so that any buffers are cleared. That is, it flushes the output buffers.

void write(int ch):  Writes a single character to the invoking output stream. Note that the parameter is an int, which allows you to call write with expressions without having to cast them back to char.

void write(char buffer[ ]):  Writes a complete array of characters to the invoking output stream.

abstract void write(char buffer[ ], int offset, int numChars):  Writes a subrange of numChars characters from the array buffer, beginning at buffer[offset] to the invoking output stream.

void write(String str):  Writes str to the invoking output stream.

void write(String str, int offset, int numChars):  Writes a subrange of numChars characters from the array str, beginning at the specified offset.


The following example shows how to read lines from a file and print these to the standard output stream. It reads its own source file, which must be in the current directory.

  // Demonstrate FileReader.
  import java.io.*;

  class FileReaderDemo {
    public static void main(String args[]) throws Exception {
      FileReader fr = new FileReader("FileReaderDemo.java");
      BufferedReader br = new BufferedReader(fr);
      String s;

      while((s = br.readLine()) != null) {
        System.out.println(s);
      }
      
      fr.close();
    }
  }


FileWriter

FileWriter creates a Writer that you can use to write to a file. Its most commonly used constructors are shown here:

      FileWriter(String filePath)
      FileWriter(String filePath, boolean append)
      FileWriter(File fileObj)
      FileWriter(File fileObj, boolean append)

They can throw an IOException. Here, filePath is the full path name of a file, and fileObj is a File object that describes the file. If append is true, then output is appended to the end of the file. The fourth constructor was added by Java 2, version 1.4.

Creation of a FileWriter is not dependent on the file already existing. FileWriter will create the file before opening it for output when you create the object. In the case where you attempt to open a read-only file, an IOException will be thrown.

The following example is a character stream version of an example shown earlier when FileOutputStream was discussed. This version creates a sample buffer of characters by first making a String and then using the getChars( ) method to extract the character array equivalent. It then creates three files. The first, file1.txt, will contain every other character from the sample. The second, file2.txt, will contain the entire set of characters. Finally, the third, file3.txt, will contain only the last quarter.

  // Demonstrate FileWriter.
  import java.io.*;

  class FileWriterDemo {
    public static void main(String args[]) throws Exception {
      String source = "Now is the time for all good men\n"
        + " to come to the aid of their country\n"
        + " and pay their due taxes.";
      char buffer[] = new char[source.length()];
      source.getChars(0, source.length(), buffer, 0);

      FileWriter f0 = new FileWriter("file1.txt");
      for (int i=0; i < buffer.length; i += 2) {
        f0.write(buffer[i]);
      }
      f0.close();

      FileWriter f1 = new FileWriter("file2.txt");
      f1.write(buffer);
      f1.close();

      FileWriter f2 = new FileWriter("file3.txt");

      f2.write(buffer,buffer.length-buffer.length/4,
               buffer.length/4);
      f2.close();
    }
  }


CharArrayReader

CharArrayReader is an implementation of an input stream that uses a character array as the source. This class has two constructors, each of which requires a character array to provide the data source:

      CharArrayReader(char array[ ])
      CharArrayReader(char array[ ], int start, int numChars)

Here, array is the input source. The second constructor creates a Reader from a subset of your character array that begins with the character at the index specified by start and is numChars long.

The following example uses a pair of CharArrayReaders:

  // Demonstrate CharArrayReader.
  import java.io.*;

  public class CharArrayReaderDemo {
    public static void main(String args[]) throws IOException {
      String tmp = "abcdefghijklmnopqrstuvwxyz";
      int length = tmp.length();
      char c[] = new char[length];

      tmp.getChars(0, length, c, 0);
      CharArrayReader input1 = new CharArrayReader(c);
      CharArrayReader input2 = new CharArrayReader(c, 0, 5);

      int i;
      System.out.println("input1 is:");
      while((i = input1.read()) != -1) {
        System.out.print((char)i);
      }
      System.out.println();

      System.out.println("input2 is:");
      while((i = input2.read()) != -1) {
        System.out.print((char)i);
      }
      System.out.println();
    }
  }

The input1 object is constructed using the entire lowercase alphabet, while input2 contains only the first five letters. Here is the output:

  input1 is:
  abcdefghijklmnopqrstuvwxyz
  input2 is:
  abcde


CharArrayWriter

CharArrayWriter is an implementation of an output stream that uses an array as the destination. CharArrayWriter has two constructors, shown here:

      CharArrayWriter( )
      CharArrayWriter(int numChars)

In the first form, a buffer with a default size is created. In the second, a buffer is created with a size equal to that specified by numChars. The buffer is held in the buf field of CharArrayWriter. The buffer size will be increased automatically, if needed. The number of characters held by the buffer is contained in the count field of CharArrayWriter. Both buf and count are protected fields.

The following example demonstrates CharArrayWriter by reworking the sample program shown earlier for ByteArrayOutputStream. It produces the same output as the previous version.

  // Demonstrate CharArrayWriter.
  import java.io.*;

  class CharArrayWriterDemo {
    public static void main(String args[]) throws IOException {
      CharArrayWriter f = new CharArrayWriter();
      String s = "This should end up in the array";
      char buf[] = new char[s.length()];

      s.getChars(0, s.length(), buf, 0);
      f.write(buf);
      System.out.println("Buffer as a string");
      System.out.println(f.toString());
      System.out.println("Into array");

      char c[] = f.toCharArray();
      for (int i=0; i<c.length; i++) {
        System.out.print(c[i]);
      }

      System.out.println("\nTo a FileWriter()");
      FileWriter f2 = new FileWriter("test.txt");
      f.writeTo(f2);
      f2.close();
      System.out.println("Doing a reset");
      f.reset();
      for (int i=0; i<3; i++)
        f.write('X');
      System.out.println(f.toString());
    }
  }


BufferedReader

BufferedReader improves performance by buffering input. It has two constructors:

      BufferedReader(Reader inputStream)
      BufferedReader(Reader inputStream, int bufSize)

The first form creates a buffered character stream using a default buffer size. In the second, the size of the buffer is passed in bufSize.

As is the case with the byte-oriented stream, buffering an input character stream also provides the foundation required to support moving backward in the stream within the available buffer. To support this, BufferedReader implements the mark( ) and reset( ) methods, and BufferedReader.markSupported( ) returns true.

The following example reworks the BufferedInputStream example, shown earlier, so that it uses a BufferedReader character stream rather than a buffered byte stream. As before, it uses mark( ) and reset( ) methods to parse a stream for the HTML entity reference for the copyright symbol. Such a reference begins with an ampersand (&) and ends with a semicolon (;) without any intervening whitespace. The sample input has two ampersands, to show the case where the reset( ) happens and where it does not. Output is the same as that shown earlier.

  // Use buffered input.
  import java.io.*;

  class BufferedReaderDemo {
    public static void main(String args[]) throws IOException {
      String s = "This is a &copy; copyright symbol " +
        "but this is &copy not.\n";
      char buf[] = new char[s.length()];
      s.getChars(0, s.length(), buf, 0);
      CharArrayReader in = new CharArrayReader(buf);
      BufferedReader f = new BufferedReader(in);
      int c;
      boolean marked = false;

      while ((c = f.read()) != -1) {
        switch(c) {
        case '&':
          if (!marked) {

            f.mark(32);
            marked = true;
          } else {
            marked = false;
          }
          break;
        case ';':
          if (marked) {
            marked = false;
            System.out.print("(c)");
          } else
            System.out.print((char) c);
          break;
        case ' ':
          if (marked) {
            marked = false;
            f.reset();
            System.out.print("&");
          } else
            System.out.print((char) c);
          break;
        default:
          if (!marked)
              System.out.print((char) c);
          break;
        }
      }
    }
  }


BufferedWriter

A BufferedWriter is a Writer that adds a flush( ) method that can be used to ensure that data buffers are physically written to the actual output stream. Using a BufferedWriter can increase performance by reducing the number of times data is actually physically written to the output stream.

A BufferedWriter has these two constructors:

      BufferedWriter(Writer outputStream)
      BufferedWriter(Writer outputStream, int bufSize)

The first form creates a buffered stream using a buffer with a default size. In the second, the size of the buffer is passed in bufSize.


PushbackReader

The PushbackReader class allows one or more characters to be returned to the input stream. This allows you to look ahead in the input stream. Here are its two constructors:

      PushbackReader(Reader inputStream)
      PushbackReader(Reader inputStream, int bufSize)

The first form creates a buffered stream that allows one character to be pushed back. In the second, the size of the pushback buffer is passed in bufSize.

PushbackReader provides unread( ), which returns one or more characters to the nvoking input stream. It has the three forms shown here:

      void unread(int ch)
      void unread(char buffer[ ])
      void unread(char buffer[ ], int offset, int numChars)

The first form pushes back the character passed in ch. This will be the next character returned by a subsequent call to read( ). The second form returns the characters in buffer. The third form pushes back numChars characters beginning at offset from buffer. An IOException will be thrown if there is an attempt to return a character when the pushback buffer is full.

The following program reworks the earlier PushBackInputStream example by replacing PushBackInputStream with a PushbackReader. As before, it shows how a programming language parser can use a pushback stream to deal with the difference between the == operator for comparison and the = operator for assignment.

  // Demonstrate unread().
  import java.io.*;

  class PushbackReaderDemo {
    public static void main(String args[]) throws IOException {
      String s = "if (a == 4) a = 0;\n";
      char buf[] = new char[s.length()];
      s.getChars(0, s.length(), buf, 0);
      CharArrayReader in = new CharArrayReader(buf);
      PushbackReader f = new PushbackReader(in);
      int c;

      while ((c = f.read()) != -1) {
        switch(c) {
        case '=':
          if ((c = f.read()) == '=')
            System.out.print(".eq.");
          else {
            System.out.print("<-");
            f.unread(c);
          }
          break;
        default:
          System.out.print((char) c);
          break;
        }
      }
    }
  }


PrintWriter

PrintWriter is essentially a character-oriented version of PrintStream. It provides the formatted output methods print( ) and println( ). PrintWriter has four constructors:

      PrintWriter(OutputStream outputStream)
      PrintWriter(OutputStream outputStream, boolean flushOnNewline)
      PrintWriter(Writer outputStream)
      PrintWriter(Writer outputStream, boolean flushOnNewline)

where flushOnNewline controls whether Java flushes the output stream every time println( ) is called. If flushOnNewline is true, flushing automatically takes place. If false, flushing is not automatic. The first and third constructors do not automatically flush.

Java’s PrintWriter objects support the print( ) and println( ) methods for all types, including Object. If an argument is not a simple type, the PrintWriter methods will call the object’s toString( ) method and then print out the result.

No comments:

Post a Comment