Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Core Java Classes, Input and Output Streams

Java Programming, Lesson # 60, Revised 12/18/98.

Preface

Students in Prof. Baldwin's Intermediate Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.

As of 1/9/98 the programs named files02.java and stream02.java still use deprecated APIs from JDK 1.0.2. However, the programs named SampProg151 and SampProg152 in the Review section at the end of the lesson show how to rewrite these two programs and eliminate the use of deprecated APIs.

The Java 1.1 class library provides two different types of I/O classes -- byte-oriented and character-oriented.

The two types of streams are organized into two separate class hierarchies, one consisting of the byte-oriented stream classes, and the other consisting of character-oriented stream classes. The classes within the two hierarchies have the same names, except for their suffix.

The byte-oriented stream classes end in either InputStream or OutputStream, while the character-oriented stream classes end in either Reader or Writer.

The two hierarchies are functionally almost identical, and they contain most of the same subclass specializations.

Most of the programs in this lesson use InputStream or OutputStream. However, the two program mentioned above that illustrate how to eliminate deprecated APIs use the Reader and Writer classes for character-oriented data. Also, a good reference for learning more about this topic is the article entitled Use the two "R"s of Java 1.1 -- Readers and Writers - JavaWorld - November 1997.

In September of 1998, a new section was added near the end of this lesson that deals with the new Reader and Writer classes.  It contains one sample program that shows how to convert the sample program named files02.java into a character-stream program using Reader and Writer classes.

A good reference for learning more about this topic is the article entitled Use the two "R"s of Java 1.1 -- Readers and Writers - JavaWorld - November 1997.

Several new classes were added to JDK 1.1 that deal with I/O of entire objects. The names of the classes usually contain the word Object. Some of these classes are discussed in a subsequent lesson on object serialization.
 

Introduction

According to The Java Tutorial by Mary Campione and Kathy Walrath, http://java.sun.com/books/Series/Tutorial/java/io/index.html
 
"A stream is a flowing sequence of characters."
Usually the task is to move data from memory to an external device or vice versa, but not necessarily. Streams can also be used to move data from one part of memory to another part of memory just as well.

It has been said that through the use of streams, it is the responsibility of the computer to move bytes from one place to another without regard for the meaning associated with those bytes.

It is the responsibility of the programmer to assign meaning to the bytes.

For example, a group of 32 bytes could represent 32 pieces of graphic data, or 8 integer values; the stream I/O system doesn't usually know and doesn't care.

Only the programmer and the user know and care what the 32 bytes are meant to represent.

In other words, a stream is usually considered to be an abstraction for the capability to move bytes from a source to a sink.

We have previously seen examples of moving bytes from the keyboard (standard input device) to the computer's memory, and have seen examples of moving bytes from the computer's memory to the screen (standard output device).

We have also touched on the need to move bytes between disk files and the computer's memory.

In a later lesson, we will look at the requirement for and the techniques available to move bytes between the memory and a network.

All of these examples involve the use of streams.

The package named java.io contains a set of input and output stream classes that can be used to read and write data.

The InputStream class and OutputStream class are abstract superclasses that define the behavior for sequential input and output streams in Java.

The java.io package also provides specialized InputStream and OutputStream subclasses that are used for specialized types of input and output.

We will examine each of the classes, discuss how to use them, and how to subclass them for your own purposes.
 
 

Getting Started with I/O Streams

You are already familiar with the use of standard input, standard output, and standard error as provided by the System class.

For example, we have been using the following code fragments since the beginning of the Introductory course:
 
System.out.println("my output string");
While (System.in.read() != -1) ...
According to The Java Tutorial:
 
System.out refers to an output stream managed by the System class that implements the standard output system.
System.out is an instance (an object) of the PrintStream class defined in the java.io package. The PrintStream class is a subclass of OutputStream.

The OutputStream Class

According to Java in a Nutshell by David Flanagan, the OutputStream class is an abstract class which is the superclass of all output streams. It defines the basic output methods that all output streams provide. The following methods are defined in the OutputStream class.
 
close() - Closes the stream. 
flush() - Flushes the stream. 
write(int) - Writes a byte. 
write(byte[]) - Writes an array of bytes. 
write(byte[], int, int) - Writes a sub array of bytes.
.

The PrintStream Class

The Java specification, which is available on-line at JavaSoft, http://java.sun.com/ provides the following description for the PrintStream class:
 
A PrintStream adds functionality to another output stream -- namely, the ability to print representations of various data values conveniently. 

Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested by the checkError method. 

Optionally, a PrintStream can be created so as to "autoflush"; this means that after an array of bytes is written, or after a single byte equal to '\n' is written, the flush method is automatically invoked.

The following methods are included in the list of methods available to objects of the PrintStream class of which the out object in the System class is an instance.

These are the methods of the System.out stream object.
 
checkError() - Flushes the print stream and returns whether or not there was 
an error on the output stream. 
close() - Closes the stream. 
flush() - Flushes the stream. 

print(various argument types) - Prints the argument. 

println(various argument types) - Prints the argument. 
println(String) Prints a string followed by a newline. 

write(int) - Writes a byte. 
write(byte[], int, int) - Writes a sub array of bytes.

The println(String) method which we have used extensively in example programs in previous lessons is highlighted in boldface above. There are many other available methods as well.

Recall that when we first used System.out.println(String), we explained that we were invoking the println() method of the out object which is a class variable of the System class.

Since the out object is of type PrintStream, all of the methods listed above are available to the out object.

Because it is a class variable, we can access it and its methods without first instantiating an object of the System class.

Java in a Nutshell indicates that the PrintStream class extends a class known as FilterOutputStream. We will deal with filtering later in this lesson.

Note that the System class is not part of java.io. Rather, it is part of java.lang.

The hierarchy relative to the object named out is
 
  • Object is the class from which all other classes are derived 
    • OutputStream is a subclass of Object
      • FilterOutputStream is a subclass of OutputStream. 
        • PrintStream is a subclass of FilterOutputStream
          • System contains a class variable named out of type PrintStream
All classes in Java are subclasses of Object at some level. Each level of inheritance between the class named Object and the class variable named out adds methods and variables. The object named out contains all the methods and variables contributed by all of its ancestors.

Reference Material

Part of the difficulty of programming in Java is establishing and understanding class hierarchies as described above. Java in a Nutshell is an excellent reference in this regard.

The Java language Specification, the API Specification, and a lot of other useful information is also available at Sun's JavaSoft page http://java.sun.com/ in other formats.

You should avail yourself of one or more of these sources plus other good sources that you identify if you plan to program successfully in Java.
 
 

Standard Input

Now let's examine the following commonly-used code fragment with an eye toward the hierarchy.
 
While (System.in.read() != -1) ...
Here, we are invoking the read() method of the object referred to by in which is a class variable of the System class. The System class has three class variables: As seen in an earlier lesson, the System class also has about a dozen class methods which can be invoked without a requirement to instantiate an object of the class.

The InputStream class (of which the object referenced by in is an instance) is a subclass of the Object class and has considerably fewer methods than the PrintStream class (of which the object referenced by out is an instance).

The InputStream contains three overloaded public versions of read(); the one shown above and two which deal with arrays of type byte. All three throw IOException.

Peter Norton's Guide to Java Programming indicates that the form of read() which takes no arguments attempts to read and return a single byte from the input stream, cast as an integer. If there is nothing more to be read, it returns a -1. The fact that the byte is returned cast as an integer needs to be taken into account when using this method.

The following description of the read() method which takes no parameters comes from JavaSoft's Java Language specification (emphasis added by this author).
 
The general contract of read is that it reads one byte from the input stream. The byte is returned as an integer in the range 0 to 255 (0x00-0xff). If no byte is available because the stream is at end of file, the value -1 is returned

This method blocks until input data is available, end of file is detected, or an exception is thrown. 

If the byte cannot be read for any reason other than end of file, an IOException is thrown. In particular, an IOException is thrown if the input stream has been closed

Similar material regarding the other overloaded versions of the read() method is also available in the Java Language Specification.

The hierarchy for the object in is (approximately)
 
  • Object is the class from which all other classes are derived 
    • InputStream is an abstract subclass of the class Object 
      • in is a class variable of type InputStream 
While we know that it is not possible to instantiate objects of abstract classes (such as InputStream), this structure suggests that it is possible to define class variables (such as in) which reference abstract classes, which in turn causes the class methods of the abstract class to become available by way of the class variable.

According to Java in a Nutshell, InputStream is the superclass of all input streams and it defines the basic input methods that all input stream classes provide.
 
 

Hierarchy Diagrams for I/O Streams

Most of the other classes in the java.io package derive from two classes: InputStream and OutputStream (also see the comment in the Preface section regarding readers and writers)

The InputStream class defines methods for

OutputStream defines methods for writing bytes or arrays of bytes to the stream.

Input and output streams are automatically opened when you instantiate an object of the proper type. Several example programs will be provided later which show the opening of input and output streams.

You can close an input stream or an output stream by using the close() method. Otherwise, it will be closed when the stream object is garbage collected.

Recall that objects become eligible for garbage collection when they are no longer referenced by an object reference variable but there is generally no guarantee that garbage collection will occur before the program terminates.

Both InputStream and OutputStream have several subclasses that implement specific input and output functions.

The hierarchy structure for InputStream is shown in the first of the following two diagrams.

The hierarchy structure for OutputStream is shown in the second diagram.
 
Object

        InputStream

                FileInputStream

                PipedInputStream

                FilterInputStream (abstract)

                        DataInputStream

                        BufferedInputStream

                        LineNumberInputStream

                        PushbackInputStream

                ByteArrayInputStream

                SequenceInputStream

                StringBufferInputStream
.
 
Object

        OutputStream

                FileOutputStream

                PipedOutputStream

                FilterOutputStream (abstract)

                        DataOutputStream

                        BufferedOutputStream

                        PrintStream

                ByteArrayOutputStream
A non-exhaustive description of some of the classes in the above diagram follows.

FileInputStream

This is a subclass of InputStream that reads data from a file specified by name or by a File or FileDescriptor object. While it is possible to read data using objects of this class, it is more common to use an object of type DataInputStream which is a type of FilterInputStream that allows you to read lines of text and Java primitive data types in a portable way.

You can create a DataInputStream by specifying the InputStream that is to be filtered in the call to the constructor.
 
 

FileOutputStream

This is a subclass of OutputStream that writes data to a file specified by name or by a File or FileDescriptor object. This is a low-level class. You would typically use a DataOutputStream or PrintOutputStream to filter output to a FileOutputStream. DataOutputStream is a subclass of FilterOutputStream that allows you to write Java primitive data types in a portable way.

You can create a DataOutputStream by specifying the OutputStream that is to be filtered in the call to the constructor.
 
 

PipedInputStream

This class is an InputStream that implements one-half of a pipe, and is useful for communication between threads. A PipedInputStream must be connected to a PipedOutputStream object, which may be specified when the PipedInputStream is created, or with the connect() method.

Data read from a PipedInputStream object is received from the PipedOutputStream to which it is connected.
 
 

PipedOutputStream

Implements the other half of a pipe (see PipedInputStream above). Similar connection requirement apply.

ByteArrayInputStream

An object of this class provides input data from a specified array of byte values. This is useful when you want to read data in memory as if it were coming from a file, pipe, or socket. (Similar to a StringBufferInputStream.)

ByteArrayOutputStream

Data that is written is stored in an internal byte array which grows as necessary, and can be retrieved using toByteArray() or toString().

The reset() method discards any data currently stored in the array and begins storing data from the beginning.
 
 

SequenceInputStream

Provides a way to concatenate the data from two or more input streams. Provides an interface to a sequence of InputStream objects. Data is read from the streams in the order in which the streams are specified.

StringBufferInputStream

Data comes from the characters of a specified String object. Useful to read data from memory as if it were coming from a file, a pipe, or a socket. (Similar to ByteArrayInputStream.)

Filtered Streams

The following classes derive from FilterInputStream and FilterOutputStream which are both abstract classes. These classes define the interface for filtered streams which process data as it's being read or written.

DataInputStream

Allows you to read lines of text and Java primitive data types in a portable way. Possibly the most commonly used class for file input. A DataInputStream object provides facilities for reading bytes from an input source and interpreting specific character sequences as representing data of diverse types. Many methods for translating from byte sequences to data types are described in the Java Language Specification.

BufferedInputStream

Provides input data buffering which increases efficiency by reading in large amounts of data and storing them in an internal buffer.

LineNumberInputStream

Keeps track of the number of lines of data that have been read. The getLineNumber() method returns the current line number. The setLineNumber() method sets the line number of the current line and subsequent lines are numbered starting from that number.

PushbackInputStream

Implements a one-byte pushback buffer. The unread() method "pushes" one character back into the stream, which will be the first one read by the next call to a read() method.

BufferedOutputStream

Provides output data buffering which increases efficiency by storing values to be written in a buffer and actually writing them out when the buffer fills or when the flush() method is called.

PrintStream

A PrintStream adds functionality to another output stream -- namely, the ability to print representations of various data values conveniently. More detailed information regarding this class was provided earlier in this lesson.

Note that according to Java in a Nutshell, this method does not handle Unicode data. The class discards the top 8 bits of all 16-bit Unicode characters.
 
 

DataOutputStream

Provides facilities for converting data of diverse types into character sequences of specific formats that are then sent to some output stream.

Miscellaneous Classes

The java.io package contains other classes in addition to the stream classes.

File

Provides a platform-independent definition of file and directory names. Also provides methods useful for performing a number of utility operations on files. For example, you can create a File object for a file on the native file system and then query the object for information about that file (such as its full pathname).

FileDescriptor

Platform independent representation of a low-level handle to an open file or an open socket. According to the Java Language Specification
 
A FileDescriptor is an opaque representation of a connection to an actual file in a file system, or to a network socket, or to another source or sink of bytes. The main practical use for a file descriptor is to create a FileInputStream or FileOutputStream to contain it.
.

RandomAccessFile

Allows reading and writing of arbitrary bytes, text, and primitive Java data types from or to any specified location in a file. Not a subclass of InputStream or OtputStream. Rather RandomAccessFile is an entirely independent method for reading and writing data from and to files. A large number of methods are provided.

You may have noticed that unlike other languages, thus far, we have not made mention of an ability to append data to an existing file. In order to append data to an existing file in Java, you must treat it as a random access file.
 
 

StreamTokenizer

Performs lexical analysis of a specified input stream and breaks the contents of a stream into tokens.

Interfaces

The java.io package defines three interfaces which are implemented by a variety of classes.

DataInput

Declares the methods required for streams that can read character data or Java primitive data types in a machine-independent format.

DataOutput

Declares the methods required for streams that can write character data or Java primitive data types in a machine-independent format.

FilenameFilter

Declares the accept() method that must be implemented by any object that filters filenames (selects a subset of filenames from a list of filenames).

Reading and Writing Files using Streams

To perform file I/O in Java, you must instantiate a stream object of the appropriate type and link it to a device.

As you can see from the following program, writing and reading sequential files in Java is fairly straightforward.
 
/* File files01.java Copyright 1997, R.G.Baldwin

This application illustrates writing and then reading a 

file one byte at a time.



The instantiation of a file stream object is illustrated 

using two different approaches:

1.  Using a literal string containing the name of the file.

2.  Using an object of type File containing the name of 

the file.



Also illustrates use of the methods of the File class to

inquire about the properties of the file:  absolute path 

and length.



The output from the program is:



Start the program and write a file

Get info on, read, and print the file

Path is C:\BALDWIN\Java\SampProg\Java\junk.txt

Length 4

Dick

End of program

**********************************************************/



import java.io.*;



class files01{

  public static void main(String[] args)

  {

    System.out.println(

                    "Start the program and write a file");

    try{

    //Instantiate and initialize an output file stream 

    // object using a string containing the name of the 

    // file.

    FileOutputStream outFile = 

                          new FileOutputStream("junk.txt");

  

    //Write four bytes to the file and close it

    outFile.write('D');

    outFile.write('i');

    outFile.write('c');

    outFile.write('k');

    outFile.close();

  }catch(IOException e){}



    System.out.println(

                  "Get info on, read, and print the file");

  

  //Instantiate an object of type file containing the name

  // of the file.

  File junkFile = new File("junk.txt");

  

  //Use the File object to get info about the file

  System.out.println(

                 "Path is " + junkFile.getAbsolutePath());

  System.out.println("Length " + junkFile.length() );

  

  //Now read and print the data in the file

  try{

    //Instantiate and initialize the stream object using 

    // the File object.

    FileInputStream inFile = new FileInputStream(junkFile);

    int data;

  

    //Read and print until eof indicated by -1.  read() 

    // method returns integer.  Must cast as char to print.

    // Otherwise, the numeric value of the byte is 

    // displayed.

    while( (data = inFile.read()) != -1)

      System.out.print((char)data);

    inFile.close();

  }catch(IOException e){}

  System.out.println(); //new line

  System.out.println("End of program");

  }// end main



}//end class files01 definition

Implementing Pipes using Streams

Pipes may be used to cause the output of one thread in a program to feed into the input of another thread. The input and output components of a pipe are implemented by PipedInputStream and PipedOutputStream.

The following application instantiates and runs two threads. One of the threads places integer data into a PipedOutputStream object which is connected to a PipedInputStream object. The other thread receives its input from the PipedInputStream object.

The thread which generates the integers implements a random time delay between the output of successive integers to allow the other thread an opportunity to gain control of the system. Otherwise, depending on the platform being used, the first thread might hog the system until it completes its task. (Some implementations of the JVM provide for time-slicing between threads of equal priority while other implementations do not.)

The thread which receives the integers terminates when it receives a -1 from the input object indicating end of file. Note that the end of file is generated automatically by the system when the thread that generates the integers completes its task.

A main function is used to instantiate the stream objects, instantiate the thread objects, and start the threads running.

There are a couple of interesting things to note about this program. First, it implements an operation very similar to the producer/consumer program in an earlier lesson on interrupts, but in a much simpler way.

Second, even though all three threads have finalizer methods that announce that the thread is being finalized (immediately prior to garbage collection) there is no finalizer message produced by the main thread.
 
/* File pipe01.java Copyright 1997, R.G.Baldwin

This Java application illustrates the piping of the output

from one thread to the input of another thread.



The SenderThread sends the integers 0, 1, 2, and 3 with 

pauses in between.  The ReceiverThread receives and sums 

the integers.



The actual sequence of data in the output depends on the 

values obtained from the random number generator used to 

produce pauses.  



Tested using JDK 1.1.3 under Win95.



For one particular run, the output was as 

follows:



Starting SenderThread

Sending 0

Starting ReceiverThread

Received 0

Sum = 0

Sending 1

Received 1

Sum = 1

Sending 2

Sending 3

Received 2

Sum = 3

Received 3

Sum = 6

SenderThread done

ReceiverThread done, sum = 6

Finalizing sender thread

Finalizing receiver thread

**********************************************************/

import java.io.*;



class SenderThread extends Thread{

  //Piped output stream obj init by constructor

  PipedOutputStream pos; 



  //-----------------------------------------------------//

  

  //Constructor

  public SenderThread(PipedOutputStream posIn){

    pos = posIn; //save piped output stream object

  }//end SenderThread constructor

  //-----------------------------------------------------//



  public void run(){ //this method runs as a thread

    System.out.println("Starting SenderThread");

    try{

      for( int i = 0; i < 4; i++){

        //write a byte to the piped output stream

        pos.write(i); 

        System.out.println("Sending " + i);

        try{//sleep for awhile

          sleep((int)(Math.random() * 1000)); 

        }catch(InterruptedException e){}

      }//end for loop

    }catch(IOException e){}

    System.out.println("SenderThread done");

  }//end run() method

  //-----------------------------------------------------//

  

  public void finalize(){

    System.out.println("Finalizing sender thread");

  }//end finalize

  //-----------------------------------------------------//



}//end SenderThread class definition

//=======================================================//





class ReceiverThread extends Thread{

  //piped input stream obj init by constructor

  PipedInputStream inputStream; 

  int sum = 0, inData = 0; //working variables

  //-----------------------------------------------------//

  

  //Constructor

  public ReceiverThread(PipedInputStream inStream){

    //save piped input stream object

    inputStream = inStream; 

  }//end ReceiverThread constructor

  //-----------------------------------------------------//



  public void run(){ //this method runs as a thread

    System.out.println("Starting ReceiverThread");

    try{

      //read the first byte as an integer

      inData = inputStream.read(); 

      System.out.println("Received " + inData);

      while (inData != -1){ 

        //read until integer -1 signals no more data

        sum += inData; //accumulate the sum

        System.out.println("Sum = " + sum);

        //read next byte as an integer

        inData = inputStream.read(); 

        System.out.println("Received " + inData);

      }//end while loop

    }catch(IOException e){}

    System.out.println(

                      "ReceiverThread done, sum = " + sum);

  }//end run() method

  

  public void finalize(){

    System.out.println("Finalizing receiver thread");

  }//end finalize

  //-----------------------------------------------------//



}//end ReceiverThread class definition

//=======================================================//



class pipe01{ //controlling class

  public static void main(String[] args){

    System.runFinalizersOnExit(true);

    try{

      //Instantiate a PipedInputStream object

      PipedInputStream inStr = new PipedInputStream();

  

      //Instantiate a PipedOutputStream object and connect 

      // it to the existing PipedInputStream object

      PipedOutputStream pos = new PipedOutputStream(inStr);

  

      //Instantiate two thread objects

      SenderThread T1 = new SenderThread(pos );

      ReceiverThread T2 = new ReceiverThread(inStr );



      //And start the threads running  

      T1.start();

      T2.start();

    }catch(IOException e){}  

  }//end main()

  //-----------------------------------------------------//



  public void finalize(){

    System.out.println("Finalizing main thread");

  }//end finalize

  //-----------------------------------------------------//

}//end pipe01 class definition

Using Filtered Streams

We are going to take a look at filtered streams at this point because that information will be useful later.

The filtered stream classes make it possible for you to apply I/O filtering to data being processed by an object of an unfiltered stream class. For example, you could create a custom filter object to read a file and convert all the characters to upper case.

Filtered stream classes are subclasses of the abstract classes named FilterInputStream and FilterOutputStream.

There are several standard filtered streams available, and you can create your own. Those which are in the standard java.io package are:

The characteristics of each of these classes were discussed earlier.

To use a filtered stream class, you must associate an object of the filtered stream class with an object of the unfiltered stream class that will handle your I/O. You do this by instantiating an object of the filtered class by passing an object of the unfiltered class to the constructor for the filtered class.

You can instantiate the object of the unfiltered class beforehand, or you can simply call the constructor for the unfiltered class as a parameter to the constructor for the filtered class (create it as an anonymous object).

Having done this, you then have access to all the methods of the filtered class to use in your I/O efforts.

The following sample application is a rewrite of the previous application named files01.java. In the previous application, it was necessary to perform I/O one byte at a time. In this rewrite, The DataInputStream and DataOutputStream classes are associated with the FileInputStream and FileOutputStream classes. This makes it possible to use the methods of DataInputStream and DataOutputStream to control the I/O process.

This in turn makes it possible to perform the I/O one string at a time rather than one byte at a time. Numerous other methods are also available to perform the I/O in different ways.

Note that this program uses deprecated methods. The program named SampProg151 in the Review section at the end of the lesson shows how to replicate this program with no deprecated methods.
 
/* File files02.java Copyright 1997, R.G.Baldwin

This application is a modification of the application named

files01.  The purpose is to illustrate the use of filtered

I/O classes to write and then read a file, one string at a

time.



Objects of types DataOutputStream and DataInputStream are 

instantiated using objects of types FileOutputStream and

FileInputStream as parameters to the constructor.  This 

makes all of the methods for objects of types 

DataOutputStream and DataInputStream available to write 

and read the file.



The program was tested using JDK 1.1.3 under Win95.



The output from the program is:



Start the program and write a file

Get info about, read, and print the file

Path is C:\BALDWIN\Java\SampProg\Java\junk.txt

Length 13

Dick

Baldwin

End of program

**********************************************************/



import java.io.*;



class files02{

  public static void main(String[] args)

  {

    System.out.println(

                    "Start the program and write a file");

    try{



      //Instantiate and initialize a DataOutputStream 

      // object using a FileOutputStream object as a 

      // parameter to the constructor. This makes it 

      // possible to write to the file using the methods

      // of the DataOutputStream class.

      DataOutputStream dataOut = 

        new DataOutputStream(

                        new FileOutputStream("junk.txt"));

  

      //Write two strings to the file and close it

      dataOut.writeBytes("Dick\n");

      dataOut.writeBytes("Baldwin\n");

      dataOut.close();

    }catch(IOException e){}



    System.out.println(

              "Get info about, read, and print the file");

  

    //Instantiate an object of type file containing the 

    // name of the file.  Same as app named files01.java.

    File junkFile = new File("junk.txt");

  

    //Use the File object to get info about the file. 

    // Same as files01.java.

    System.out.println(

                 "Path is " + junkFile.getAbsolutePath());

    System.out.println("Length " + junkFile.length() );

  

    //Now read and print the data in the file

    try{

      //Instantiate a DataInputStream object on the 

      // FileInputStream object which uses the File object

      // named junkFile to open the stream and link to 

      // the file.

            

      //Note that the compiler reports readLine() as a

      // deprecated method and suggests using methods 

      // from the reader class instead.

      

      DataInputStream inData = 

        new DataInputStream(new FileInputStream(junkFile));



      String data; //temp holding area

  

      //Read and print strings until eof is indicated by 

      // null.  

      while( (data = inData.readLine()) != null)

        System.out.println(data);

      inData.close();

    }catch(IOException e){}

    System.out.println("End of program");

  }// end main

}//end class files02 definition

Reading and Writing Memory Buffers using Streams

The unfiltered classes ByteArrayInputStream and StringBufferInputStream make it possible for you to read data from memory buffer areas as though you were reading from an external device.

ByteArrayOutputStream can be used to write data into a memory buffer as though it were an external device.

ByteArrayInputStream and ByteArrayOutputStream will allow you to read and write 8-bit data. When you create these streams, you specify an existing byte array and then use the read() and write() methods to read from or write data to the array in memory.

StringBufferInputStream allows you to to read data from a String object. When you create a StringBufferInputStream object, you specify an existing String object as the source of the data and then use the read() methods to read from that object.

The following program illustrates the use of a StringBufferInputStream object to read the contents of a String object. Note that even though this class is named StringBufferInputStream, it is not designed to read the contents of objects of type StringBuffer.

Note that the following program uses deprecated code. The program named SampProg152.java in the Review section shows how to replicate this program without using any deprecated code.
 
/* File stream02.java

This application illustrates the use of a 

StringBufferInputStream object to read the contents of an

object of type String.



Note that even though this class is called 

StringBufferInputStream it does not read the contents of

objects of type StringBuffer.  Rather, the data source 

must be an object of type String.



The output from the program is:



Start the program and create a String object.

Create stream object of type StringBufferInputStream.

Read and display the contents of the String object.

This is an object of type String.

End of program

**********************************************************/

import java.io.*;

  

class stream02{//controlling class

  public static void main(String[] args)

  {

    System.out.println(

         "Start the program and create a String object.");

    String myString = "This is an object of type String.";

        

    System.out.println("Create stream object of type " +

                              "StringBufferInputStream.");

                              

    //Note that StringBufferInputStream is deprecated.  The

    // documentation recommends using the StringReader

    // class instead.

    StringBufferInputStream myStream = 

                    new StringBufferInputStream(myString);



    System.out.println("Read and display the contents " +

                                 "of the String object.");

          for(int cnt = 0; cnt < myString.length(); cnt++)

            System.out.print((char)myStream.read());

        

        System.out.println("\nEnd of program");

  }// end main

}//end class stream02 definition

Creating Your Own Filtered Stream Classes

The steps for creating your own filtered stream classes include the following: The following application provides custom filtered input and output classes which make it possible to write objects of a specific type to a disk file and read them back.

A custom version of a write method is provided which decomposes the object into a series of bytes and writes those bytes to the file.

A custom version of a read method is provided which reads bytes from the file and reconstructs an object.

The user of the classes simply writes and reads objects and doesn't need to be concerned about the details of how the data is being handled.
 
/* File stream01.java Copyright 1997, R.G.Baldwin

This application illustrates the creation of custom filter

classes to filter I/O.  The classes can write objects of

type MyData to a disk file and read them back.



This application extends FilterOutputStream and 

FilterInputStream to implement the new filter classes.



The new filter output class named MyFilterOutputClass 

contains a method named MyWrite()



The MyWrite method accepts an input object of type MyData,

  converts it to a stream of bytes and writes them onto

  the disk using the write(int b) method of 

  FileOutputStream



The general contract for write is that one byte is written

  to the output stream. The byte to be written is the 

  eight low-order bits of the argument b which is an 

  integer. The 24 high-order bits of the integer b are 

  ignored.  



The individual bytes for the int data member named intData

  are selected and passed to the write() method by 

  shifting bits to the right 3 times, 8 bits per shift



This class does not override the write() method.  Rather,

  it provides a new MyWrite() method which makes use of 

  one form of the existing write() method.



The program was tested using JDK 1.1.3 under Win95.



The output from the program is:



Start the program and write an object to file

Read the object from the file and display it

The file contains X 123456789

End of program

**********************************************************/

import java.io.*;



class MyData{//data structure used for testing

  public char charData;

  public int intData;



  public MyData(){}//default constructor

  

  //parameterized constructor

  public MyData(char inChar, int inIntData){

    charData = inChar;

  intData = inIntData;

  }//end constructor

}//end class MyData definition

//=======================================================//



//This is a custom filter class for writing objects of

// type MyData into a file.

class MyFilterOutputClass extends FilterOutputStream{



  MyFilterOutputClass(FileOutputStream out) //constructor

  { super(out);} //pass the output object up the line

  

  //This is the new write method for objects

  void MyWrite(MyData obj){

    try{

      //write the character data member to the file

      write(obj.charData);

  

      //Now use bit shifting to decompose the integer 

      // data member into bytes and write them to the file

      for(int cnt = 0; cnt < 4; cnt++)

        write( (int) obj.intData >> 8*cnt);

    }catch(IOException e){}

  }//end write(MyData obj)

}//end MyFilterOutputClass definition

//=======================================================//



//This is a custom filter class for reading bytes from

// a file and constructing them into objects of type 

// MyData.

class MyFilterInputClass extends FilterInputStream{

  MyFilterInputClass(FileInputStream in) //constructor

  { super(in);} //pass the output object up the line



  //The following method reads bytes from a file and 

  // constructs an object of type MyData.  The object is

  // returned to the calling method.

  MyData MyRead(){

    MyData obj = new MyData();

    try{//read char data member from the file

      obj.charData = (char)read();

  

      //Now read bytes from the file and construct 

      // the integer data member

      for(int cnt = 0; cnt < 4; cnt++)

        obj.intData = obj.intData | 

                    ( (char)read()<< 8*cnt); //next 8 bits

    }catch(IOException e){}

    return obj; //return the constructed object

  }//end MyRead()

}//end MyFilterOutputClass definition

//=======================================================//

  

class stream01{//controlling class

  public static void main(String[] args){

    System.out.println(

          "Start the program and write an object to file");



    //Instantiate new type filter out obj linked to 

    // FileOutputStream

    try{

      MyFilterOutputClass fileOut = 

        new MyFilterOutputClass( 

                        new FileOutputStream("junk.txt") );

    

      //Construct an object of type MyData

      MyData myObject = new MyData('X',123456789);

    

      //Use new type filter method to write the object 

      // to the file

      fileOut.MyWrite(myObject);

      fileOut.close();

    }catch(IOException e){}



    System.out.println(

           "Read the object from the file and display it");

    //Instantiate new type filter inp obj linked to 

    // FileInputStream

    try{

      MyFilterInputClass fileIn = 

        new MyFilterInputClass( 

                         new FileInputStream("junk.txt") );

    

      //Use new filter method to read object from file

      MyData inData = fileIn.MyRead();

      fileIn.close();

  

      //Display the contents of the object

      System.out.println("The file contains " + 

                   inData.charData + " " + inData.intData);

    }catch(IOException e){}



    System.out.println("End of program");

  }// end main

}//end class stream01 definition

Reading and Writing Random Access Files

The previous discussions have been concerned with sequential input/output. That is, input and output where the bytes are transferred as a sequential stream of bytes. This is a particularly appropriate form of I/O for communication with other computers via the network, etc.

However, when working with disk files, it is often desirable to be able to treat the data in the file as an an "array" of bytes and to be able to access those bytes anywhere within the array. This can be accomplished using the random access capabilities afforded by Java

Note that unlike other languages, the classes that we have been studying do not allow for appending data to the end of a file. In order to append data to the end of a file in Java, you must treat that file as a random access file.

Random access of file data in Java is supported by the RandomAccessFile class.
 
 

Using Random Access Files

The RandomAccessFile class can be used both for reading and writing. It implements the DataInput and DataOutput interfaces.

As with the sequential FileInputStream and FileOutputStream classes, you specify a file to be opened by name when you instantiate an object of class RandomAccessFile. You can specify the file name either by a literal string or by passing a File object which you have previously instantiated.

Unlike with the sequential classes, when you instantiate an object of RandomAccessFile, you must indicate whether you will just be reading the file, or also writing to it. You must be able to read a file before you can write to it.

The syntax for instantiating a RandomAccessFile object is as follows:
 
new RandomAccessFile(name, mode)
As mentioned earlier, the name can be specified using either a literal string or an object of type File. The mode is a literal string which can be either of two possibilities:

Once the file is opened you can use the various forms of the read___() and write___() methods to read and write the data in the file.

Simply being able to use the read and write methods to read or write the data in the file wouldn't be very interesting except for the availability of some additional methods. In particular, as in other languages which support random file I/O, RandomAccessFile supports the notion of a file pointer.

The file pointer points to the current location in the file. It points to the beginning of the file (value of 0) when the object is first instantiated. When you use the normal read and write methods, the value of the pointer is adjusted by the number of bytes actually read or written.

In addition, there are three methods available to explicitly manipulate the file pointer:

Random Access Files and Filters

As with sequential file I/O, we often want to be able to apply filtering to the data when we read and write a file on a random basis. Because RandomAccessFile doesn't inherit from the InputStream or OutputStream classes, you can't apply the same filters to objects of RandomAccessFile that you apply to the sequential streams.

However, because RandomAccessFile implements the DataInput and DataOutput interfaces, you can create a filter that works for either DataInput or DataOutput and it will work on those sequential access files that implement DataInput or DataOutput as well as any RandomAccessFile.
 
 

A Sample Program

The following sample program illustrates the use of the RandomAccessFile class to read and write bytes interior to a file.
 
/* File files03.java Copyright 1997, R.G.Baldwin

This application is a modification of the application 

named files02.  The purpose is to illustrate the use of 

the RandomFileAccess class to read and write data interior 

to the file.



Tested using JDK 1.1.3 under Win95



The output from the program is:



Start the program and write a file

Now open and read the file in random access mode

Display the entire file as characters.

Dick

Baldwin

Now display four bytes interior to the file.

Bald

Now write four bytes interior to the file.

Now display the entire file again.

Note that four bytes have been overwritten.

Dick

WXYZwin



End of program

**********************************************************/



import java.io.*;



class files03{

  public static void main(String[] args)

  {

    System.out.println(

                     "Start the program and write a file");

    try{



      //Instantiate and initialize a DataOutputStream 

      // object using a FileOutputStream object as a 

      // parameter to the constructor. This makes it 

      // possible to write to the file using the methods

      // of the DataOutputStream class.  This is a 

      // sequential stream operation and NOT a random 

      // access operation.

      DataOutputStream dataOut = new DataOutputStream(

                         new FileOutputStream("junk.txt"));

  

      //Write two strings to the file and close it

      dataOut.writeBytes("Dick\n");

      dataOut.writeBytes("Baldwin\n");

      dataOut.close();

    }catch(IOException e){}



    //Instantiate an object of type file containing the 

    // name of the file to illustrate the use of File 

    // objects in instantiating an object later of type 

    // RandomAccessFile

    File junkFile = new File("junk.txt");

  

    System.out.println(

       "Now open and read the file in random access mode");

    try{

      //Instantiate a RandomAccesSfile object for reading 

      // and writing using the File object named junkFile

      // to open and link to the file.

      RandomAccessFile inData = 

                       new RandomAccessFile(junkFile,"rw");

      int temp;



      System.out.println(

                 "Display the entire file as characters.");

      //Note that the file pointer is initially at the 

      // beginning of the file.

      while( (temp = inData.read()) != -1)

        System.out.print((char)temp);

  

      System.out.println(

           "Now display four bytes interior to the file.");

      //Get current location of the file pointer.

      long filePointer = inData.getFilePointer();

  

      //Set the file pointer to a location interior to 

      // the file.

      inData.seek(filePointer-8);

  

      //Now read and display four bytes.

      for(int cnt = 0; cnt < 4; cnt++)

        System.out.print( (char)inData.read() );

  

      System.out.println(

           "\nNow write four bytes interior to the file.");

      filePointer = inData.getFilePointer();

      inData.seek(filePointer-4);

      for(int cnt = 0; cnt < 4; cnt++)

        inData.write('W'+cnt);

  

      System.out.println(

                     "Now display the entire file again.");

      System.out.println(

            "Note that four bytes have been overwritten.");

      //Note that it is necessary to reposition the file 

      // pointer to the beginning of the file.

      inData.seek(0);

      while( (temp = inData.read()) != -1)

        System.out.print((char)temp);

  

      inData.close();

    }catch(IOException e){}

    System.out.println("\nEnd of program");

  }// end main

}//end class files03 definition
.

Reader and Writer Classes

The Reader and Writer classes were added to JDK 1.1 to support internationalization.  Briefly, the stream I/O capability that was supported prior to that release didn't support the use of 16-bit Unicode characters.  Rather, only the bottom 8 bits were handled by the streams.

The Reader and Writer classes make it possible to work with character streams rather than byte streams.  To a large extent, these character-stream classes mirror the byte stream classes, so if you know how to use one, it isn't too difficult to figure out how to use the other.  The web is full of discussions regarding the pros and cons of this situation, so I won't discuss it further at this point.  Rather, I am simply going to provide a sample program that will show you how to upgrade the previous program named files02.java to cause it to use character streams instead of byte streams.

To understand the differences, you should compare the code in this program with the code in files02.java.

Some of the code in the original program had nothing to do with the difference between byte streams and character streams, so that code was omitted from this version.

A listing of the program follows.  I have highlighted the new and important parts of this version in boldface to make it easier for you to compare this version with the original version.
/* File files04.java Copyright 1998, R.G.Baldwin

This program is an upgrade to the program named

files02.  The purpose is to convert the original program

that used byte streams for input and output to one that

uses unicode character streams for input and output.



To understand the differences, you should compare the

code in this program with the code in files02.java.



Some of the code in the original program had nothing to

do with the difference between byte streams and character

streams, so that code was omitted from this version.



The output from the program is:



Start the program and write a file

Read and print the file

Dick

Baldwin

End of program





The program was tested using JDK 1.1.6 under Win95.

**********************************************************/



import java.io.*;



class files04{

  public static void main(String[] args)

  {

    System.out.println(

                    "Start the program and write a file");

    try{

      //Open an output character stream using the Writer

      // classes.

      PrintWriter dataOut = 

         new PrintWriter(new FileWriter("junk.txt"),true);



      dataOut.println("Dick");

      dataOut.println("Baldwin");

  

      dataOut.close();



      System.out.println("Read and print the file");

      //Open an input character stream using the Reader

      // classes.

      BufferedReader inData = 

           new BufferedReader(new FileReader("junk.txt"));



      String data; //temp holding area

      while( (data = inData.readLine()) != null)

        System.out.println(data);

      inData.close();

    }catch(IOException e){}

    System.out.println("End of program");

  }// end main

}//end class files04 definition

Hopefully, this sample program will provide you with enough information to be able to convert your thinking and your programs from byte streams to character streams.
 

Review

Q - Usually the task of a stream is to move data from memory to an external device or vice versa, but streams can also be used to move data from one part of memory to another part of memory just as well: True or False. If false, explain why.

A - True.

Q - Write a Java application that illustrates writing and then reading a file one byte at a time. Instantiate your file stream objects using a literal string containing the name of the file. The output from the program should be similar to the following:
 
Start the program and write a file
Read, and display the file
Dick
End of program
A - See the program below:
 
/* File SampProg110.java from lesson 60

Copyright 1997, R.G. Baldwin

Without viewing the solution which follows, write a Java

application that illustrates writing and then reading a 

file one byte at a time.



=========================================================//

*/

import java.io.*;



class SampProg110{

  public static void main(String[] args){

    System.out.println(

    "Start the program and write a file");

    try{

      //Instantiate and initialize an output file stream 

      // object using a literal string containing the name

      // of the file.

      FileOutputStream outFile = new FileOutputStream(

        "junk.txt");

        

      //Write four bytes in the file and close it

      outFile.write('D');

      outFile.write('i');

      outFile.write('c');

      outFile.write('k');

      outFile.close();

    }catch(IOException e){}

    

    System.out.println("Read, and display the file");  

      

    //Now read and print the data in the file

    try{

      FileInputStream inFile = new FileInputStream(

        "junk.txt");

      int data;

        

      //Read and print until eof indicated by -1.  read() 

      // method returns integer.  Must cast as char to 

      // print. Otherwise, the numeric value of the byte 

      // is displayed.

      while( (data = inFile.read()) != -1)

        System.out.print((char)data);

      inFile.close();

    }catch(IOException e){}

    System.out.println();//new line

    System.out.println("End of program");

  }// end main

}//end class SampProg110 definition
Q - Write a Java application that illustrates writing and then reading a file one byte at a time. Store the uppercase characters A, B, C, D, and E in the file. Display the numeric unicode values of the characters. Instantiate your file stream object using an object of type File. Also use the object of type File to obtain and display two properties of the file: absolute path and length The output from the program should be similar to the following:
 
Start the program and write a file
Get info about, read, and print the file
Path is C:\BALDWIN\Cis2103K\Fall97\SampProg\junk.txt
Length 5
65 66 67 68 69 
End of program
A - See the program below.
 
/* File SampProg111.java from lesson 60

Copyright 1997, R.G.Baldwin

Without viewing the solution that follows, write a Java

application that illustrates writing and then reading a 

file one byte at a time.



=========================================================//

*/



import java.io.*;



class SampProg111{

  public static void main(String[] args)

  {

    System.out.println(

                     "Start the program and write a file");

    //Instantiate an object of type File

    File fileObj = new File("junk.txt");

        

    try{

      //Instantiate and initialize the stream object 

      // using the File object.

      FileOutputStream outFile = 

        new FileOutputStream(fileObj);

    

      //Write five bytes to the file and close it

      outFile.write('A');

      outFile.write('B');

      outFile.write('C');

      outFile.write('D');

      outFile.write('E');

      outFile.close();

    }catch(IOException e){}



    System.out.println(

      "Get info about, read, and print the file");  

    

    //Use the File object to get info about the file

    System.out.println("Path is " 

      + fileObj.getAbsolutePath());

    System.out.println("Length " + fileObj.length() );

  

    //Now read and print the data in the file

    try{

      //Instantiate and initialize the stream object 

      // using the File object.

      FileInputStream inFile = 

                              new FileInputStream(fileObj);

      int data;

  

      //Read and print until eof indicated by -1.  

      // read() method returns integer.  

      while( (data = inFile.read()) != -1)

        System.out.print(data + " ");

      inFile.close();

    }catch(IOException e){}

    System.out.println(); //new line

    System.out.println("End of program");

  }// end main

}//end class SampProg111 definition
Q - Write a Java application that illustrates the piping of the output from one thread to the input of another thread. The SenderThread sends the message "Dick Baldwin". The ReceiverThread receives and displays the message.

The output from your program should be similar to the following:
 
Starting ReceiverThread 
Starting SenderThread 
Received: Dick Baldwin 
ReceiverThread done 
A - See program below.
 
/* File SampProg112.java from lesson 60

Copyright 1997, R.G.Baldwin



Without viewing the following solution, write a Java

application that illustrates the piping of the output from 

one thread to the input of another thread.

=========================================================//

*/

import java.io.*;



class SenderThread extends Thread{

  PipedOutputStream pos; //ref to piped output stream obj

  String msgToSend = "Dick Baldwin";



  public SenderThread(PipedOutputStream posIn){

    pos = posIn; //save ref to piped output stream object

  }//end SenderThread constructor



  public void run(){ //override run method

    System.out.println("Starting SenderThread");

    try{

      for( int i = 0; i < msgToSend.length(); i++){

        //write a character to the piped output stream

        pos.write(msgToSend.charAt(i)); 

      }//end for loop

    }catch(IOException e){}

    //SenderThread has finished its task here

  }//end run() method

}//end SenderThread class definition



class ReceiverThread extends Thread{

  //ref to piped input stream obj

  PipedInputStream inputStr; 

  int inData = 0; //working variable

  

  public ReceiverThread(PipedInputStream inStr){

    inputStr = inStr; //save ref to piped input stream obj

  }//end ReceiverThread constructor



  public void run(){ //override run method

    System.out.println("Starting ReceiverThread");

    try{

      //read the first character as an integer

      inData = inputStr.read();

      System.out.print("Received: " + (char)inData);

      //read until integer -1 signals no more data

      while (inData != -1){ 

        //read next char as an integer

        inData = inputStr.read();

        System.out.print((char)inData);//display it

      }//end while loop

    }catch(IOException e){}

    System.out.println();//new line

    System.out.println("ReceiverThread done");

  }//end run() method

}//end ReceiverThread class definition





class SampProg112{ //controlling class

  public static void main(String[] args){

    try{

      //Instantiate a PipedInputStream object

      PipedInputStream inStr = new PipedInputStream();

  

      //Instantiate a PipedOutputStream object and connect 

      // it to the existing PipedInputStream object

      PipedOutputStream pos = new PipedOutputStream(inStr);

  

      //Instantiate two thread objects

      SenderThread T1 = new SenderThread(pos );

      ReceiverThread T2 = new ReceiverThread(inStr );



      //And start the threads running  

      T2.start();

      T1.start();

    }catch(IOException e){}  

  }//end main()

}//end SampProg112 class definition
Q - Write a Java application that writes a double, a long, and a character to a file and then reads the file and displays the data.

The output from the program should be similar to the following:
 
Start the program and write a file 
Read, and print the file 
Double: 3.14159 
Long: 1234 
Character: X 
End of program
A - See program below.
 
/* File SampProg113.java from lesson 60

Copyright 1997, R.G.Baldwin



Without viewing the solution that follows, write a Java

application that writes a double, a long, and a character

to a file and then reads the file and displays the data.

=========================================================//

*/



import java.io.*;



class SampProg113{

  public static void main(String[] args)

  {

    System.out.println(

      "Start the program and write a file");

    try{



      //Instantiate and initialize a DataOutputStream 

      // object using a FileOutputStream object as a 

      // parameter to the constructor. This makes it 

      // possible to write to the file using the

      // methods of the DataOutputStream class.

      DataOutputStream dataOut = 

        new DataOutputStream(

          new FileOutputStream("junk.txt"));



      //Write a double, a long, and a character to the file

      dataOut.writeDouble(3.14159);

      dataOut.writeLong(1234);

      dataOut.writeChar('X');

    }catch(IOException e){}



    System.out.println("Read, and print the file");  

  

    //Now read and print the data in the file

    try{

      //Instantiate a DataInputStream object on the 

      // FileInputStream object

      DataInputStream inData = 

        new DataInputStream(

          new FileInputStream("junk.txt"));

    

      //Read and print a double, a long, and a character

      System.out.println("Double: " + inData.readDouble());

      System.out.println("Long: " + inData.readLong());

      System.out.println("Character: " + inData.readChar());

      inData.close();

    }catch(IOException e){}

    System.out.println("End of program");

  }// end main

}//end class SampProg113 definition
Q - Write a Java application that writes a double, a long, and a character to an array of bytes in memory, and then reads the three data elements from the byte array and displays their values.

The output from the program should be similar to the following:
 
Write formatted data to a ByteArrayOutputStream object 
Read and display formatted data from the byte array 
Double: 3.14159 
Long: 1234 
Character: X 
End of program 
A - See the program below.
 
/* File SampProg114.java from lesson 60

Copyright 1997, R.G.Baldwin



This application illustrates the use of 

ByteArrayOutputStream and ByteArrayInputStream in 

conjunction with filtered I/O classes to write and then

read formatted data of specific mixed types into an array

of bytes in memory.



An object of type DataOutputStream is instantiated using

an object of type ByteArrayOutputStream as a parameter to

the constructor.  This makes all of the methods for objects

of type DataOutputStream available to write formatted data

into the memory represented by the ByteArrayOutputStream 

object.



A double, a long, and a character are written to the 

ByteArrayOutputStream object.



Then, an ordinary byte array is extracted from the

ByteArrayOutputStream object which contains the bytes

representing the double, the long, and the character.



This byte array is passed to a ByteArrayInputStream

constructor creating an object that is passed in turn to

a DataInputStream object.  This makes all of the methods

for objects of type DataInputStream available to read data

from the memory represented by the ByteArrayInputStream

object.



The double, long, and character data are read and 

displayed.



The output from the program should be similar to the 

following:

  

Write formatted data to a ByteArrayOutputStream object

Read and display formatted data from the byte array

Double: 3.14159

Long: 1234

Character: X

End of program

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

*/



import java.io.*;



class SampProg114{

  public static void main(String[] args)

  {

    System.out.println(

      "Write formatted data to a " 

        + "ByteArrayOutputStream object");

    //Instantiate the ByteArrayOutputStream object

    ByteArrayOutputStream myByteArrayOutputStream = 

      new ByteArrayOutputStream();

    try{

      //Instantiate and initialize a DataOutputStream 

      // object using the ByteArrayOutputStream object as a

      // parameter to the constructor. This makes it 

      // possible to write to the ByteArrayOutputStream 

      // object using the methods of the DataOutputStream 

      // class.

      DataOutputStream dataOut = 

        new DataOutputStream(myByteArrayOutputStream);



      //Write a double, a long, and a character to 

      // the ByteArrayOutputStream object  

      dataOut.writeDouble(3.14159);

      dataOut.writeLong(1234);

      dataOut.writeChar('X');

    }catch(IOException e){}

    

    //Extract an ordinary byte array from the 

    // ByteArrayOutputStream object to use below.

    byte[] myByteArray = 

      myByteArrayOutputStream.toByteArray();



    System.out.println(

     "Read and display formatted data from the byte array");

  

    try{

      //Instantiate a DataInputStream object on a 

      // ByteArrayInputStream object linked to the

      // ordinary byte array.  This makes it possible to

      // use the methods of the DataInputStream class to

      // read formatted data from the byte array.

      DataInputStream inData = 

        new DataInputStream(

          new ByteArrayInputStream(myByteArray));

    

      //Read and display a double, a long, and a character

      // from the byte array.

      System.out.println("Double: " + inData.readDouble());

      System.out.println("Long: " + inData.readLong());

      System.out.println("Character: " + inData.readChar());

      inData.close();

    }catch(IOException e){}

    

    System.out.println("End of program");

  }// end main

}//end class SampProg114 definition
Q - Write a Java application that instantiates an object of a user-defined type containing a single String data member, writes the object to a file as a stream of bytes, reads the stream of bytes from the file and reconstructs the object, and then displays the String data member.

The output from this program should be similar to the following:
 
Start the program and write an object to file 
Read the object from the file and display it 
The file contains First String 
End of program 
A - See program below.
 
/* File SampProg115.java from lesson 60



Copyright 1997, R.G.Baldwin



This application illustrates the creation of custom filter

classes to filter I/O.  The two custom filter classes can 

write objects of type MyData to a disk file and read them 

back.



This application extends FilterOutputStream and 

FilterInputStream to implement the new filter classes.



The new filter output class named MyFilterOutputClass 

contains a method named MyWrite()



The MyWrite method accepts an input object of type MyData,

converts it to a stream of bytes and writes them onto the

disk.



The output from this program should be similar to the

following:

  

Start the program and write an object to file

Read the object from the file and display it

The file contains First String

End of program  

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

*/

import java.io.*;



class MyData{//data structure used for testing

  public String firstString = "First String";

}//end class MyData definition

//=========================================================



//This is a custom filter class for writing objects of

// type MyData into a file.

class MyFilterOutputClass extends FilterOutputStream{

  MyFilterOutputClass(FileOutputStream out) //constructor

  { super(out);} //invoke superclass constructor

  

  //This is the new write method for objects

  void MyWrite(MyData obj){

    try{

      //write the string as a byte array     

      write(obj.firstString.getBytes());

    }catch(IOException e){}

  }//end write(MyData obj)

}//end MyFilterOutputClass definition

//=========================================================



//This is a custom filter class for reading bytes from

// a file and constructing them into an object 

// of type MyData.

class MyFilterInputClass extends FilterInputStream{

  MyFilterInputClass(FileInputStream in) //constructor

  { super(in);} //invoke superclass constructor



  //This is the new read method for objects. This method 

  // reads bytes from a file and constructs an object of 

  // type MyData.  The object is returned to the calling 

  // function.

  MyData MyRead(){

    MyData obj = new MyData();//construct empty object

    //Try to populate it by reading bytes and converting

    // them into a string.

    try{

      byte[] tempByteArray = new byte[40];

      in.read(tempByteArray);

      obj.firstString = new String(tempByteArray);

    }catch(IOException e){}

    return obj; //return the constructed object

  }//end MyRead()

}//end MyFilterOutputClass definition

//=========================================================

 

class SampProg115{//controlling class

  public static void main(String[] args){//main method

    System.out.println(

      "Start the program and write an object to file");

    

    //Instantiate new type filtered output obj linked to 

    // FileOutputStream

    try{

      MyFilterOutputClass fileOut = 

        new MyFilterOutputClass(

          new FileOutputStream("junk.txt") );

      

      //Construct an object of type MyData

      MyData myObject = new MyData();

      

      //Use new type filter method to write the object 

      // to the file

      fileOut.MyWrite(myObject);

      fileOut.close();

    }catch(IOException e){}



    System.out.println(

      "Read the object from the file and display it");

    //Instantiate new type filter input obj linked 

    // to FileInputStream

    try{

      MyFilterInputClass fileIn = 

        new MyFilterInputClass(

          new FileInputStream("junk.txt") );

      

      //Use new filter method to read object from file

      MyData inData = fileIn.MyRead();

      fileIn.close();

    

      //Display the contents of the object

      System.out.println("The file contains " 

        + inData.firstString);

    }catch(IOException e){}



    System.out.println("End of program");

    

  }// end main

}//end class SampProg115 definition
Q - Write a Java application that modifies four bytes interior to a file, displaying the contents of the file before and after the modification.

The output from the program should be similar to the following:
 
Start the program and write a file in sequential mode 
Now open and read the file in random access mode 
Display the entire file as characters. 
First String 
Second String 
Now display four bytes interior to the file. 
nd S 
Now write four bytes interior to the file. 
Now display the entire file again. 
Note that four bytes have been overwritten. 
First String 
SecoABCDtring
A - See the program below.
 
/* File SampProg116.java from lesson 60

Copyright 1997, R.G.Baldwin



First write a file containing two strings in sequential

mode and close the file.



Then open and display all the bytes in the file in random

access mode.



Then display four bytes interior to the file.



The modify the same four bytes interior to the file and 

display them again.



The output from the program should be similar to the

following:



Start the program and write a file in sequential mode

Now open and read the file in random access mode

Display the entire file as characters.

First String

Second String

Now display four bytes interior to the file.

nd S

Now write four bytes interior to the file.

Now display the entire file again.

Note that four bytes have been overwritten.

First String

SecoABCDtring



End of program

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

*/



import java.io.*;



class SampProg116{

  public static void main(String[] args)

  {

    System.out.println(

      "Start the program and write a file in " 

        + "sequential mode");

    try{

      //Instantiate and initialize a DataOutputStream 

      // object using a FileOutputStream object as a 

      // parameter to the constructor. 

      DataOutputStream dataOut = 

        new DataOutputStream(

          new FileOutputStream("junk.txt"));

    

      //Write two strings to the file and close it

      dataOut.writeBytes("First String\n");

      dataOut.writeBytes("Second String\n");

      dataOut.close();

    }catch(IOException e){}



    System.out.println(

      "Now open and read the file in random access mode");

    try{

      //Instantiate a RandomAccesSfile object for reading 

      // and writing and link it to the file that was

      // created above.

      RandomAccessFile inData = 

        new RandomAccessFile("junk.txt","rw");

      int temp;

  

      System.out.println(

        "Display the entire file as characters.");

      //Note that the file pointer is initially at the 

      // beginning of the file.

      while( (temp = inData.read()) != -1)

        System.out.print((char)temp);

    

      System.out.println(

        "Now display four bytes interior to the file.");

      //Get current location of the file pointer.

      long filePointer = inData.getFilePointer();

    

      //Set the file pointer to a location interior 

      // to the file.

      inData.seek(filePointer - 10);

    

      //Now read and display four bytes.

      for(int cnt = 0; cnt < 4; cnt++)

        System.out.print( (char)inData.read() );

    

      System.out.println(

        "\nNow write four bytes interior to the file.");

      filePointer = inData.getFilePointer();

      inData.seek(filePointer - 4);



      for(int cnt = 0; cnt < 4; cnt++)

        inData.write('A'+cnt);

    

      System.out.println(

        "Now display the entire file again.");

      System.out.println(

        "Note that four bytes have been overwritten.");

      //Note that it is necessary to reposition the 

      // file pointer to the beginning of the file.

      inData.seek(0);



      while( (temp = inData.read()) != -1)

        System.out.print((char)temp);

    

      inData.close();

    }catch(IOException e){}

    System.out.println("\nEnd of program");

  }// end main

}//end class SampProg116 definition
Q - Write a Java program that meets the following specifications.
 
/* File SampProg151.java Copyright 1997, R.G.Baldwin

From lesson 60.



Without viewing the solution that follows, write a Java

application that replicates the program named files02.java

but doesn't use deprecated methods.



This application is a modification of the application named

files01.  The purpose is to illustrate the use of filtered

I/O classes to write and then read a file, one string at a

time.



The program was tested using JDK 1.1.3 under Win95.



The output from the program is:



Start the program and write a file

Get info about, read, and print the file

Path is C:\BALDWIN\Java\SampProg\Java\junk.txt

Length 13

Dick

Baldwin

End of program

**********************************************************/



import java.io.*;



class SampProg151{

  public static void main(String[] args)

  {

    System.out.println(

                    "Start the program and write a file");

    try{



      //Instantiate and initialize a DataOutputStream 

      // object using a FileOutputStream object as a 

      // parameter to the constructor. This makes it 

      // possible to write to the file using the methods

      // of the DataOutputStream class.

      DataOutputStream dataOut = 

        new DataOutputStream(

                        new FileOutputStream("junk.txt"));

  

      //Write two strings to the file and close it

      dataOut.writeBytes("Dick\n");

      dataOut.writeBytes("Baldwin\n");

      dataOut.close();

    }catch(IOException e){}



    System.out.println(

              "Get info about, read, and print the file");

  

    //Instantiate an object of type file containing the 

    // name of the file.  Same as app named files01.java.

    File junkFile = new File("junk.txt");

  

    //Use the File object to get info about the file. 

    // Same as files01.java.

    System.out.println(

                 "Path is " + junkFile.getAbsolutePath());

    System.out.println("Length " + junkFile.length() );

  

    //Now read and print the data in the file

    try{

      //Instantiate a BufferedReader object on the 

      // FileReader object which uses the File object

      // named junkFile to open the stream and link to 

      // the file.

            

      /*The following note was extracted from the JDK 1.1.3

      documentation:

      Note: readLine() is deprecated. This method does not

      properly convert bytes to characters. As of 

      JDK 1.1, the preferred way to read lines of text is 

      via the BufferedReader.readLine() method. Programs 

      that use the DataInputStream class to read lines can

      be converted to use the BufferedReader class by 

      replacing code of the form

      

          DataInputStream d = new DataInputStream(in); 

      with 

          BufferedReader d

            = new BufferedReader(

              new InputStreamReader(in)); 

      */

      BufferedReader inData =

        new BufferedReader(new FileReader(junkFile));



      String data; //temp holding area

  

      //Read and print strings until eof is indicated by 

      // null.  

      while( (data = inData.readLine()) != null)

        System.out.println(data);

      inData.close();

    }catch(IOException e){}

    System.out.println("End of program");

  }// end main

}//end class SampProg151 definition
Q - Write a Java application that meets the following specifications.
 
/* File SampProg152.java Copyright 1998, R.G.Baldwin

From lesson 60



Without viewing the solution that follows, write a Java

application that replicates the program named Stream02.java

but that does not use deprecated methods.



This application illustrates the use of a StringReader 

object to read the contents of an object of type String.



The output from the program is:



Start the program and create a String object.

Create stream object of type StringReader.

Read and display the contents of the String object.

This is an object of type String.

End of program

**********************************************************/

import java.io.*;

  

class SampProg152{//controlling class

  public static void main(String[] args)

  {

    System.out.println(

         "Start the program and create a String object.");

    String myString = "This is an object of type String.";

        

    System.out.println("Create stream object of type " +

                              "StringReader.");

                              

    //Note that StringBufferInputStream is deprecated.  The

    // documentation recommends using the StringReader

    // class instead.

    StringReader myStream = 

                    new StringReader(myString);



    System.out.println("Read and display the contents " +

                                 "of the String object.");

    try{

            for(int cnt = 0; cnt < myString.length(); cnt++)

              System.out.print((char)myStream.read());

    }catch(IOException e){}

        

        System.out.println("\nEnd of program");

  }// end main

}//end class SampProg152 definition
Q - Write a Java program that meets the following specifications.
 
/*File SampProg155.java Copyright 1998, R.G.Baldwin

From lesson 60



Without viewing the solution that follows, write a Java

application that uses the new "reader" classes to read

lines of text from the keyboard and display the text

on the screen.  A line of text is terminated by pressing

the Enter key.



Continue reading and displaying lines until the user

enters "quit".



The program was tested using JDK 1.1.3 running under Win95.

**********************************************************/



import java.io.*;

//=======================================================//



public class SampProg155 {

  public static void main(String[] args){

    System.out.println(

           "Enter lines of text and they will be echoed");

    System.out.println("Enter the word quit to quit.");

    try{

      while(true){

        InputStreamReader is = 

                         new InputStreamReader(System.in);

        BufferedReader br = new BufferedReader(is);

        String s = br.readLine();

        if(s.compareTo("quit") == 0)break;

        System.out.println(s);

      }//end while

    }catch(IOException e){}

    System.out.println("Program terminated");

  }//end main

}//end class SampProg155

//=======================================================//
Q - Write a program that meets the following specifications.
 
/*File SampProg156.java

Copyright (c) Peter van der Linden,  May 5 1997.



Without viewing the solution that follows, write a Java

application that can read strings and all of the

primitive Java types from the keyboard.



This program was tested using JDK 1.1.3 under Win95.

I found it to experience intermittent problems when

used with JDK 1.1.3 under Win95.  I am assuming that

these intermittent problems will disappear when used

with a later version of the JDK. - rgb.



**********************************************************/

import java.util.*;

import java.io.*;

//=======================================================//



class SampProg156{

  public static void main(String[] args){

    EasyIn easy = new EasyIn();



    String myString;

    int myInt;

    

    System.out.println(

                "Enter a string");

    myString = easy.readString();

    System.out.println("Echo: " + myString);        

      

    System.out.println("Enter an int");

    myInt = easy.readInt();

    System.out.println("Echo: " + myInt);

    

    System.out.println("Terminating program");

        

  }//end main

}//end class SampProg156

//=======================================================//



// Simple input from the keyboard for all primitive types.

// Copyright (c) Peter van der Linden,  May 5 1997.

// Feel free to use this in your programs, as long as this

// comment stays intact.

//

// This is not thread safe, not high performance, and 

// doesn't tell EOF.

// It's intended for low-volume easy keyboard input.

// An example of use is:

//     EasyIn easy = new EasyIn();

//     int i = easy.readInt();   

// reads an int from System.in

// See Just Java and Beyond, Third Edition by Peter

// van der Linden





class EasyIn {    

  static InputStreamReader is = 

                       new InputStreamReader( System.in );

  static BufferedReader br = new BufferedReader( is );

  StringTokenizer st;



  StringTokenizer getToken() throws IOException {

    String s = br.readLine();

    return new StringTokenizer(s);

  }//end getToken()

    

  boolean readBoolean() {

    try {

      st = getToken();

      return new Boolean(st.nextToken()).booleanValue();

    }catch (IOException ioe) {

      System.err.println(

                    "IO Exception in EasyIn.readBoolean");

      return false;

    }//end catch

  }//end readBoolean()



  byte readByte(){

    try {

      st = getToken();

      return Byte.parseByte(st.nextToken());

    }catch (IOException ioe) {

      System.err.println(

                       "IO Exception in EasyIn.readByte");

      return 0;

    }//end catch

  }//end readByte()



  short readShort(){

    try {

      st = getToken();

      return Short.parseShort(st.nextToken());

    }catch (IOException ioe) {

      System.err.println(

                      "IO Exception in EasyIn.readShort");

      return 0;

    }//end catch

  }//end readShort()

    

  int readInt(){

    try {

      st = getToken();

      return Integer.parseInt(st.nextToken());

    }catch (IOException ioe) {

      System.err.println("IO Exception in EasyIn.readInt");

      return 0;

    }//end catch

  }//end readInt()



  long readLong(){

    try {

      st = getToken();

      return Long.parseLong(st.nextToken());

    }catch (IOException ioe) {

      System.err.println(

                      "IO Exception in EasyIn.readFloat");

      return 0L;

    }//end catch

  }//end readLong()



  float readFloat() {

    try {

      st = getToken();

      return new Float(st.nextToken()).floatValue();

    }catch (IOException ioe) {

      System.err.println(

                      "IO Exception in EasyIn.readFloat");

      return 0.0F;

    }//end catch

  }//end readFloat()



  double readDouble() {

    try {

      st = getToken();

      return new Double(st.nextToken()).doubleValue();

    }catch (IOException ioe) {

      System.err.println(

                     "IO Exception in EasyIn.readDouble");

      return 0.0;

    }//end catch

  }//end readDouble()



  char readChar() {

    try {

      String s = br.readLine();

      return s.charAt(0);

    }catch (IOException ioe) {

      System.err.println(

                       "IO Exception in EasyIn.readChar");

      return 0;

    }//end catch

  }//end readChar()



  String readString() {

    try {

      return br.readLine();

    }catch (IOException ioe) {

      System.err.println(

                     "IO Exception in EasyIn.readString");

      return "";

    }//end catch

  }//end readString

}//end class definition

//=======================================================//
-end-


These tutorials were developed by Richard Baldwin and are the copyrighted property of Richard Baldwin. You have permission to print one copy for your own use, but may not, without written permission from Richard Baldwin, redistribute the tutorial documents.

The base material in these lessons is believed by the author to be in the public domain. If you use these lessons for any purpose, you are using them at your own risk, and this author assumes no responsibility or liability for any damages that you may incur.

Java, Sun, HotJava and various other related symbols and names are registered trademarks of Sun Microsystems, Inc. Macintosh is a registered trademark of Apple Computer, Inc. OS/2 is a registered trademark of International Business Machines Corporation. Microsoft, MS-DOS, Visual Basic, Windows, Windows NT, Internet Explorer and Visual J++ are registered trademarks of Microsoft Corporation. Netscape and JavaScript are trademarks of Netscape Communications Corporation. All other trademarks and service marks that may have been inadvertently used in these lessons without proper credit being given are the property of their respective owners. If you feel that your trademark or copyright has been compromised, please notify this author immediately, and an appropriate correction to the document will be issued.


© 1996, 1997, 1998, 1999 Richard G. Baldwin