Byte Stream ClassesS2C Home « Byte Stream Classes
Now we have got an overview of the class hierarchies involved in Java I/O its time to investigate these classes in more detail. In our second lesson on Java I/O we take a closer look at some of the byte stream
classes that are available for our use in the java.io
package and how we use them.
The byte stream classes are the original input and output streams which were shipped with JDK 1.0
. This is the reason why System.in
, System.out
and System.err
use the
InputStream
and PrintStream
types from the byte stream classes and not the character stream classes as you would expect. The character stream classes were introduced to the language in JDK 1.1
.
The java.io.OutputStream
ClassTop
At the top of the byte output stream hierarchy is the java.io.OutputStream
abstract superclass which defines a basic set of output functions that all
byte output stream classes have. These methods allow us to flush and write bytes within the byte output stream as well as close the stream when we finish our processing. All methods
within the java.io.OutputStream
class can throw an IOException
.
The table below shows the declarations of all the methods in the java.io.OutputStream
class:
Method Declaration | Description |
---|---|
public void close() | Closes output stream and release any system resources associated with it. |
public void flush() | Flushes output stream and forces any buffered output bytes to be written out. |
public abstract void write(int b) | Writes a single byte of data specified by b to the output stream. |
public void write(bytes[] b) | Writes b bytes of data from b array. |
public void write(bytes[] b, int off, int len) | Writes len bytes of data from b array starting from off . |
write(bytes[])
ExampleTop
Lets see how we could use the write(bytes[])
method above to write a sequence of characters to the console:
/*
Write character sequence to the console
*/
import java.io.IOException; // Import the IOException class from java.io package
class WriteToConsole {
public static void main(String[] args) {
try {
byte consoleOut[] = new byte[]{'J','a','v','a','6'};
System.out.write(consoleOut);
}
catch (IOException ex) {
System.out.println("Caught IOException: " + ex);
}
}
}
Save, compile and run the WriteToConsole
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the WriteToConsole
class. Using System.out.print
and System.out.println
are a lot easier to use but you may need to write to the console this way, for some reason.
The java.io.FileOutputStream
ClassTop
We saw above how we can write bytes to the console using methods from the java.io.OutputStream
class. This doesn't really offers us anything practical when it comes to
storing information on the underlying file system. Luckily for us the subclasses in the byte output stream hierarchy give us ways to persist our data. In this part of the lesson
we examine the java.io.FileOutputStream
class which allows us to output data to a file on the system. This class offers us constuctors to write to physical files represented by File
,
FileDescriptor
and String
objects that point to the actual files on the system.
Writing To A FileTop
For our example of using the java.io.FileOutputStream
class we will create a File
object in our working directory and write some data to the file:
/*
Write character sequence output to a file using FileOutputStream
*/
import java.io.*; // Import all file classes from java.io package
class TestFileOutputStream {
public static void main(String[] args) {
byte someData[] = new byte[]{'J','a','v','a','6'}; // Our output data
FileOutputStream fos; // Our FileOutputStream
File newFile = new File("FileOutputStream.txt");
if (newFile.exists()) { // Check to see if FileOutputStream.txt already exists
System.out.println("FileOutputStream.txt already exists.");
} else {
System.out.println("Try to create FileOutputStream.txt");
try {
newFile.createNewFile(); // Create a file called FileOutputStream.txt
System.out.println("We created FileOutputStream.txt");
}
catch (IOException ex) {
System.out.println("We caught exception: " + ex);
}
}
// Open FileOutputStream.txt and output some data to it
try {
fos = new FileOutputStream(newFile); // Create a stream to write to FileOutputStream.txt
System.out.println("FileOutputStream fos has been opened.");
for (int i=0;i<someData.length;i++) {
System.out.println("Writing byte " + i + " to file");
fos.write(i);
}
fos.close();
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening FileOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to fos: " + ex);
}
}
}
Save, compile and run the TestFileOutputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestFileOutputStream
class. We print some messages to the console as we create open and write to the file.
The java.io.DataOutputStream
ClassTop
Up until this point in the lesson we have been outputting bytes either to the console or a file. What you may not be aware of is we are passing across the low-end 8 bits of data, which means that any primitive type we
pass will only have those bits passed across. Of course this is fine when we actually pass a Byte
across but for other primitive types we are not
passing across an actual representation of that primitive value, just the low-end 8 bits of it. If you read in the previous examples file "FileOutputStream.txt" and cast the bytes back to
char
primitive you will see some strange symbols displayed instead of 'java'. This is because we have lost the second lot of bits which make up a
Unicode character. Things get even worse if you try and write and then read back in other primitive types which can take up to 8 bytes of storage.
If you look at the byte output stream hierarchy, the FilterOutputStream
class is a direct subclass of the OutputStream
class that
implements all its methods. The FilterOutputStream
class is the superclass of all classes that filter output streams. These substreams sit on top of existing output streams such as the
FileOutputStream
and use the stream as a basic data sink, possibly modifying the data along the way or providing enhanced functionality. Using multiple streams in combination is known as wrapping
as essentially we wrap one stream within another.We will be using the java.io.DataOutputStream
subclass in our example below which takes an instance of FileOutputStream
in its instantiation.
This class allows us to output primitive data types to an output stream.
Writing Binary Data To A FileTop
Our example using the java.io.DataOutputStream
class will highlight the way we use a substream within a stream. We will create a File
object in our working directory and write some primitive data types to that file:
/*
Write binary data to a file using DataOutputStream
*/
import java.io.*; // Import all file classes from java.io package
class TestDataOutputStream {
public static void main(String[] args) {
// Our output data
int i = 128;
long l = 128128;
float f = 12.8f;
double d= 128.128;
DataOutputStream dos; // Our DataOutputStream
File newFile = new File("DataOutputStream.txt");
if (newFile.exists()) { // Check to see if DataOutputStream.txt already exists
System.out.println("DataOutputStream.txt already exists.");
} else {
System.out.println("Try to create DataOutputStream.txt");
try {
newFile.createNewFile(); // Create a file called DataOutputStream.txt
System.out.println("We created DataOutputStream.txt");
}
catch (IOException ex) {
System.out.println("We caught exception: " + ex);
}
}
try {
// Open DataOutputStream using a FileOutputStream as a 'wrapper'
dos = new DataOutputStream(new FileOutputStream(newFile));
System.out.println("DataOutputStream dos has been opened.");
System.out.println("Writing int " + i + " to file");
dos.writeInt(i);
System.out.println("Writing long " + l + " to file");
dos.writeLong(l);
System.out.println("Writing float " + f + " to file");
dos.writeFloat(f);
System.out.println("Writing double " + d + " to file");
dos.writeDouble(d);
dos.close();
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening DataOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to dos: " + ex);
}
}
}
Save, compile and run the TestDataOutputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestDataOutputStream
class. We print some messages to the console as we create open and write some primitives to the file.
The java.io.ObjectOutputStream
ClassTop
In our final look at the classes in the byte output stream hierarchy we look at writing objects to persistent storage using the java.io.ObjectOutputStream
class. We can overlay this stream with the FileOutputStream
to permanantly persist object state to our hard drives which we can read back at a later time using the java.io.ObjectInputStream
class.
Writing Objects To A FileTop
Our example using the java.io.ObjectOutputStream
class will highlight the way we use a substream within a stream. We will create a File
object in our working directory and write a String
and Date
object to that file:
/*
Write objects to a file using ObjectOutputStream
*/
import java.io.*; // Import all file classes from java.io package
import java.util.Date; // Import Date class from java.util package
class TestObjectOutputStream {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos; // Our ObjectInputStream
File newFile = new File("ObjectOutputStream.txt");
if (newFile.exists()) { // Check to see if ObjectOutputStream.txt already exists
System.out.println("ObjectOutputStream.txt already exists.");
} else {
System.out.println("Try to create ObjectOutputStream.txt");
try {
newFile.createNewFile(); // Create a file called ObjectOutputStream.txt
System.out.println("We created ObjectOutputStream.txt");
}
catch (IOException ex) {
System.out.println("We caught exception: " + ex);
}
}
try {
// Open ObjectOutputStream using a FileOutputStream as a 'wrapper'
oos = new ObjectOutputStream(new FileOutputStream(newFile));
oos.writeObject("Today");
System.out.println("String object written");
oos.writeObject(new Date());
System.out.println("Date object written");
oos.close();
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening ObjectOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to oos: " + ex);
}
}
}
Save, compile and run the ObjectOutputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestDataOutputStream
class. We print some messages to the console as we create open and write a String
and Date
object to a file.
The java.io.InputStream
ClassTop
At the top of the byte input stream hierarchy is the java.io.InputStream
abstract superclass which defines a basic set of input functions that all byte input stream classes have.
These methods allow us to allocate, mark, read, reset and skip bytes within the byte input stream as well as close the stream when we finish our processing. All methods within the java.io.InputStream
class apart from the mark()
and markSupported()
methods can throw an IOException
.
The table below shows the declarations of all the methods in the java.io.InputStream
class:
Method Declaration | Description |
---|---|
public int available()) | Return the number of bytes currently available that can be read or skipped. |
public void close() | Closes input stream and release any system resources associated with it. |
public void mark(int readlimit) | Mark current stream position to which we can return until readlimit has been reached. |
public boolean markSupported() | Returns true if invoking stream supports mark() and reset() methods. |
public abstract int read() | Reads next byte of data from input stream or -1 if end of file encountered. |
public int read(bytes[] b) | Reads b bytes of data into b array. |
public int read(bytes[] b, int off, int len) | Reads len bytes of data into b array starting from off . |
public void reset() | Reset the input pointer to the last mark() position. |
public long skip(long skipBytes) | Skip number of bytes specified by skipBytes and return skipBytes . |
read()
ExampleTop
Lets see how we could use the read()
method above to get byte input from the keyboard:
/*
Read byte from keyboard
*/
import java.io.IOException; // Import the IOException class from java.io package
class ReadFromKB {
public static void main(String[] args) {
try {
System.out.println("Press a key and then press Enter");
System.out.println("You pressed the " + System.in.read() + " key.");
}
catch (IOException ex) {
System.out.println("Caught IOException: " + ex);
}
}
}
Save, compile and run the ReadFromKB
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the ReadFromKB
class. The output shows entry of a small 'g' and this being processed by our program as Unicode decimal '103'.
read(bytes[])
ExampleTop
Lets see how we could use the read(bytes[])
method above to get a sequence of bytes from the keyboard:
/*
Read character sequence from keyboard
*/
import java.io.IOException; // Import the IOException class from java.io package
class ReadFromKB2 {
public static void main(String[] args) {
try {
byte kbIn[] = new byte[15];
System.out.println("Type a character sequence and then press Enter");
System.in.read(kbIn);
System.out.println("You typed in ");
for (int i=0;i<kbIn.length;i++) {
System.out.print(kbIn[i]);
}
System.out.print(" ... ");
for (int i=0;i<kbIn.length;i++) {
System.out.print((char) kbIn[i]);
}
}
catch (IOException ex) {
System.out.println("Caught IOException: " + ex);
}
}
}
Save, compile and run the ReadFromKB2
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the ReadFromKB2
class. The output shows entry of string 'javaTutor' and this being read in and processed by our program and printed out as
Unicode decimal and cast to char
primitive type.
The java.io.FileInputStream
ClassTop
We saw above how we can read bytes from the keyboard using methods from the java.io.InputStream
class. This doesn't really offers us anything practical when it comes to
reading information from the underlying file system. Luckily for us the subclasses in the byte input stream hierarchy give us ways to read our persisted data. In this
part of the lesson we examine the java.io.FileInputStream
class which offers us methods to read existing files on the system.
Reading From A FileTop
For our example of using the java.io.FileInputStream
class we will we will create a File
object to read the FileOutputStream.txt file we
created in the java.io.FileOutputStream
section above:
/*
Read input a file using FileInputStream
*/
import java.io.*; // Import all file classes from java.io package
class TestFileInputStream {
public static void main(String[] args) throws IOException {
int i;
FileInputStream fis; // Our FileOutputStream
File newFile = new File("FileOutputStream.txt");
if (newFile.exists()) { // Check to see if FileOutputStream.txt already exists
System.out.println("FileOutputStream.txt already exists.");
} else {
System.out.println("Did you run the java.io.FileOutputStream example?");
throw new IOException();
}
// Open FileInputStream.txt and read data from it
try {
fis = new FileInputStream(newFile); // Create a stream to read from FileOutputStream.txt
System.out.println("FileInputStream fis has been opened.");
do {
i = fis.read();
if (i != -1) { // The -1 value denotes the end of file condition
System.out.println("We read in character " + i);
}
} while (i != -1);
fis.close();
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening FileOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to fis: " + ex);
}
}
}
Save, compile and run the TestFileInputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestFileInputStream
class. We print some messages to the console as we create open and read from the file.
The java.io.DataInputStream
ClassTop
If you look at the byte input stream hierarchy, the FilterInputStream
class is a direct subclass of the InputStream
class that
implements all its methods. The FilterInputStream
class is the superclass of all classes that filter input streams. These substreams sit on top of existing input streams such as the
FileInputStream
and are a way or providing additional functionality to the stream. Using multiple streams in combination is known as wrapping as essentially we wrap one stream within another.
We will be using the java.io.DataInputStream
subclass in our example below which takes an instance of FileInputStream
in its instantiation. This class allows us to read primitive data types from an input stream.
Reading Binary Data From A FileTop
Our example using the java.io.DataInputStream
class will highlight the way we use a substream within a stream. We will create a File
object in our working directory and read some primitive data types from the physical representation of that file:
For our example of using the java.io.DataInputStream
class we will we will create a File
object to read the DataOutputStream.txt file we
created in the java.io.DataOutputStream
section above:
/*
Read binary data from a file using DataInputStream
*/
import java.io.*; // Import all file classes from java.io package
class TestDataInputStream {
public static void main(String[] args) throws IOException {
DataInputStream dis; // Our DataInputStream
File newFile = new File("DataOutputStream.txt");
if (newFile.exists()) { // Check to see if DataOutputStream.txt already exists
System.out.println("DataOutputStream.txt already exists.");
} else {
System.out.println("Did you run the java.io.DataOutputStream example?");
throw new IOException();
}
try {
// Open DataInputStream using a FileInputStream as a 'wrapper'
dis = new DataInputStream(new FileInputStream(newFile));
System.out.println("DataInputStream dis has been opened.");
int i = dis.readist();
System.out.println("int i = " + i);
long l = dis.readLong();
System.out.println("long l = " + l);
float f = dis.readFloat();
System.out.println("float f = " + f);
double d = dis.readDouble();
System.out.println("double d = " + d);
dis.close();
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening FileOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to dis: " + ex);
}
}
}
Save, compile and run the TestDataInputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestDataOutputStream
class. We print some messages to the console as we create open and read the primitives from the file.
The java.io.ObjectInputStream
ClassTop
In our final look at the classes in the byte input stream hierarchy we look at reading objects that were serialized and persisted to storage using the java.io.ObjectOutputStream
class.
Reading Objects From A FileTop
For our example of using the java.io.ObjectInputStream
class we will we will create a File
object to read the ObjectOutputStream.txt file
we created in the java.io.ObjectOutputStream
section above:
/*
Read serialized objects from a file using ObjectInputStream
*/
import java.io.*; // Import all file classes from java.io package
import java.util.Date; // Import Date class from java.util package
class TestObjectInputStream {
public static void main(String[] args) throws IOException {
ObjectInputStream ois; // Our ObjectInputStream
File newFile = new File("ObjectOutputStream.txt");
if (newFile.exists()) { // Check to see if ObjectOutputStream.txt already exists
System.out.println("ObjectOutputStream.txt already exists.");
} else {
System.out.println("Did you run the java.io.ObjectOutputStream example?");
throw new IOException();
}
try {
// Open ObjectInputStream using a FileInputStream as a 'wrapper'
ois = new ObjectInputStream(new FileInputStream(newFile));
String today = (String) ois.readObject();
System.out.println(today);
Date date = (Date) ois.readObject();
System.out.println(date);
ois.close();
}
catch (ClassNotFoundException ex) {
System.out.println("Class Exception: " + ex);
}
catch (FileNotFoundException ex) {
System.out.println("Exception opening ObjectOutputStream.txt : " + ex);
}
catch (IOException ex) {
System.out.println("We caught exception to ois: " + ex);
}
}
}
Save, compile and run the ObjectInputStream
test class in directory c:\_APIContents2 in the usual way.
The above screenshot shows the output of compiling and running the TestObjectInputStream
class. We print some messages to the console as we deserialize and read back in the String
and Date
objects that were serialized in the java.io.ObjectOutputStream
section above.
Lesson 5 Complete
In this lesson we took a closer look at some of the byte stream classes that are available in Java and how we use them.
What's Next?
In the next lesson we look at some of the Character stream classes that are available in Java and how we use them.