Thursday 23 March 2017

The Byte Streams - Java Tutorials ( Page 1 of 2 )

The Stream Classes

Java’s stream-based I/O is built upon four abstract classes: InputStream, OutputStream, Reader, and Writer. These classes were briefly discussed in Chapter 12. They are used to create several concrete stream subclasses. Although your programs perform their I/O operations through concrete subclasses, the top-level classes define the basic functionality common to all stream classes.

InputStream and OutputStream are designed for byte streams. Reader and Writer are designed for character streams. The byte stream classes and the character stream classes form separate hierarchies. In general, you should use the character stream classes when working with characters or strings, and use the byte stream classes when working with bytes or other binary objects.

In the remainder of this chapter, both the byte- and character-oriented streams are examined.



The Byte Streams

The byte stream classes provide a rich environment for handling byte-oriented I/O. A byte stream can be used with any type of object, including binary data. This versatility makes byte streams important to many types of programs. Since the byte stream classes are topped by InputStream and OutputStream, our discussion will begin with them.


InputStream

InputStream is an abstract class that defines Java’s model of streaming byte input. All of the methods in this class will throw an IOException on error conditions. 


The Methods Defined by InputStream

int available( ):  Returns the number of bytes of input currently available for reading.

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

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

boolean markSupported( ):  Returns true if mark( )/reset( ) are supported by the invoking stream.

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

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

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

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

long skip(long numBytes):  Ignores (that is, skips) numBytes bytes of input, returning the number of bytes actually ignored.


OutputStream

OutputStream is an abstract class that defines streaming byte output. All of the methods in this class return a void value and throw an IOException in the case of errors.


The Methods Defined by OutputStream

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

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

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

void write(byte buffer[ ]):  Writes a complete array of bytes to an output stream.

void write(byte buffer[ ], int offset, int numBytes):  Writes a subrange of numBytes bytes from the array buffer, beginning at buffer[offset].


FileInputStream

The FileInputStream class creates an InputStream that you can use to read bytes from a file. Its two most common constructors are shown here:

      FileInputStream(String filepath)
      FileInputStream(File fileObj)

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 following example creates two FileInputStreams that use the same disk file and each of the two constructors:

  FileInputStream f0 = new FileInputStream("/autoexec.bat")
  File f = new File("/autoexec.bat");
  FileInputStream f1 = new FileInputStream(f);

Although the first constructor is probably more commonly used, the second allows us to closely examine the file using the File methods, before we attach it to an input stream. When a FileInputStream is created, it is also opened for reading.

FileInputStream overrides six of the methods in the abstract class InputStream. The mark( ) and reset( ) methods are not overridden, and any attempt to use reset( ) on a FileInputStream will generate an IOException.

The next example shows how to read a single byte, an array of bytes, and a subrange array of bytes. It also illustrates how to use available( ) to determine the number of bytes remaining, and how to use the skip( ) method to skip over unwanted bytes. The program reads its own source file, which must be in the current directory.

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

  class FileInputStreamDemo {
    public static void main(String args[]) throws Exception {
      int size;
      InputStream f =
        new FileInputStream("FileInputStreamDemo.java");

      System.out.println("Total Available Bytes: " +
                         (size = f.available()));
      int n = size/40;
      System.out.println("First " + n +
                         " bytes of the file one read() at a time");
      for (int i=0; i < n; i++) {
        System.out.print((char) f.read());
      }
      System.out.println("\nStill Available: " + f.available());
      System.out.println("Reading the next " + n +
                         " with one read(b[])");
      byte b[] = new byte[n];
      if (f.read(b) != n) {
        System.err.println("couldn't read " + n + " bytes.");
      }
      System.out.println(new String(b, 0, n));
      System.out.println("\nStill Available: " + 
                         (size = f.available()));
      System.out.println("Skipping half of remaining bytes 
                         with skip()");
      f.skip(size/2);
      System.out.println("Still Available: " + f.available());
      System.out.println("Reading " + n/2 + 
                         " into the end of array");
      if (f.read(b, n/2, n/2) != n/2) {
        System.err.println("couldn't read " + n/2 + " bytes.");
      }
      System.out.println(new String(b, 0, b.length));
      System.out.println("\nStill Available: " + f.available());
      f.close();
    }
  }

Here is the output produced by this program:

  Total Available Bytes: 1433
  First 35 bytes of the file one read() at a time
  // Demonstrate FileInputStream.
  im
  Still Available: 1398

  Reading the next 35 with one read(b[])
  port java.io.*;

  class FileInputS

  Still Available: 1363
  Skipping half of remaining bytes with skip()
  Still Available: 682
  Reading 17 into the end of array
  port java.io.*;
  read(b) != n) {
  S

  Still Available: 665

This somewhat contrived example demonstrates how to read three ways, to skip input, and to inspect the amount of data available on a stream.

Java 2, version 1.4 added the getChannel( ) method to FileInputStream. This method returns a channel connected to the FileInputStream object. Channels are used by the new I/O classes contained in java.nio.


FileOutputStream

FileOutputStream creates an OutputStream that you can use to write bytes to a file. Its most commonly used constructors are shown here:

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

They can throw a FileNotFoundException or a SecurityException. Here, filePath is the full path name of a file, and fileObj is a File object that describes the file. If append is true, the file is opened in append mode. The fourth constructor was added by Java 2, version 1.4.

Creation of a FileOutputStream is not dependent on the file already existing. FileOutputStream 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 creates a sample buffer of bytes by first making a String and then using the getBytes( ) method to extract the byte array equivalent. It then creates three files. The first, file1.txt, will contain every other byte from the sample. The second, file2.txt, will contain the entire set of bytes. The third and last, file3.txt, will contain only the last quarter. Unlike the FileInputStream methods, all of the FileOutputStream methods have a return type of void. In the case of an error, these
methods will throw an IOException.

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

  class FileOutputStreamDemo {
    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.";
      byte buf[] = source.getBytes();
      OutputStream f0 = new FileOutputStream("file1.txt");
      for (int i=0; i < buf.length; i += 2) {
        f0.write(buf[i]);
      }
      f0.close();

      OutputStream f1 = new FileOutputStream("file2.txt");
      f1.write(buf);
      f1.close();

      OutputStream f2 = new FileOutputStream("file3.txt");
      f2.write(buf,buf.length-buf.length/4,buf.length/4);
      f2.close();
    }
  }

Here are the contents of each file after running this program. First, file1.txt:

  Nwi h iefralgo e
  t oet h i ftercuty n a hi u ae.

Next, file2.txt:

  Now is the time for all good men
  to come to the aid of their country
  and pay their due taxes.

Finally, file3.txt:

  nd pay their due taxes.

Java 2, version 1.4 added the getChannel( ) method to FileOutputStream. This method returns a channel connected to the FileOutputStream object. Channels are used by the new I/O classes contained in java.nio.


ByteArrayInputStream

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

      ByteArrayInputStream(byte array[ ])
      ByteArrayInputStream(byte array[ ], int start, int numBytes)

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

The following example creates a pair of ByteArrayInputStreams, initializing them with the byte representation of the alphabet:

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

  class ByteArrayInputStreamDemo {
    public static void main(String args[]) throws IOException {
      String tmp = "abcdefghijklmnopqrstuvwxyz";
      byte b[] = tmp.getBytes();
      ByteArrayInputStream input1 = new ByteArrayInputStream(b);
      ByteArrayInputStream input2 = new ByteArrayInputStream(b, 
                                                             0,3);
    }
  }

The input1 object contains the entire lowercase alphabet, while input2 contains only the first three letters.

A ByteArrayInputStream implements both mark( ) and reset( ). However, if mark( ) has not been called, then reset( ) sets the stream pointer to the start of the stream—which in this case is the start of the byte array passed to the constructor. The next example shows how to use the reset( ) method to read the same input twice. In this case, we read and print the letters “abc” once in lowercase and then again in uppercase.

  import java.io.*;

  class ByteArrayInputStreamReset {
    public static void main(String args[]) throws IOException {
      String tmp = "abc";
      byte b[] = tmp.getBytes();
      ByteArrayInputStream in = new ByteArrayInputStream(b);

      for (int i=0; i<2; i++) {
        int c;
        while ((c = in.read()) != -1) {
          if (i == 0) {
            System.out.print((char) c);
          } else {
            System.out.print(Character.toUpperCase((char) c));
          }
        }
        System.out.println();
        in.reset();
      }
    }
  }

This example first reads each character from the stream and prints it as is, in lowercase. It then resets the stream and begins reading again, this time converting each character to uppercase before printing. Here’s the output:

  abc
  ABC

No comments:

Post a Comment