Java Programming, Lesson # 60, Revised 10/11/98.
Preface
Introduction
Getting Started with I/O Streams
Hierarchy Diagrams for I/O Streams
Filtered Streams
Miscellaneous Classes
Interfaces
Reading and Writing Files using Streams
Implementing Pipes using Streams
Using Filtered Streams
Reading and Writing Memory Buffers using Streams
Creating Your Own Filtered Stream Classes
Reading and Writing Random Access Files
Reader and Writer Classes
Review
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.
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.
The Output Stream Class
The PrintStream Class
Reference Material
Standard Input
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.
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. |
.
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 print(various argument types) - Prints the argument. println(various argument types) - Prints the argument. write(int) - Writes a byte. |
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
|
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.
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. Another excellent reference is the Windows-compatible help file published by Bill Bercik at (site no longer valid).
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.
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)
|
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.
FileInputStream
FileOutputStream
PipedInputStream
PipedOutputStream
ByteArrayInputStream
ByteArrayOutputStream
SequenceInputStream
StringBufferInputStream
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.
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.
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.
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.
Implements the other half of a pipe (see PipedInputStream above). Similar connection requirement apply.
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.)
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.
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.
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.)
DataInputStream
BufferedInputStream
LineNumberInputStream
PushbackInputStream
BufferedOutputStream
PrintStream
DataOutputStream
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.
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.
Provides input data buffering which increases efficiency by reading in large amounts of data and storing them in an internal buffer.
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.
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.
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.
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.
Provides facilities for converting data of diverse types into character sequences of specific formats that are then sent to some output stream.
File
FileDescriptor
RandomAccessFile
StreamTokenizer
The java.io package contains other classes in addition to the stream classes.
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).
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. |
.
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.
Performs lexical analysis of a specified input stream and breaks the contents of a stream into tokens.
DataInput
DataOutput
FilenameFilter
The java.io package defines three interfaces which are implemented by a variety of classes.
Declares the methods required for streams that can read character data or Java primitive data types in a machine-independent format.
Declares the methods required for streams that can write character data or Java primitive data types in a machine-independent format.
Declares the accept() method that must be implemented by any object that filters filenames (selects a subset of filenames from a list of filenames).
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 |
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 |
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 |
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 |
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 |
Using Random Access Files
Random Access Files and Filters
A Sample Program
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.
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:
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.
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 |
.
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.
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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-