Recall how you read lines from the screen:
The package java.io contains the classes
InputStreamReader and LineNumberReader.
java.io contains more than 50 classes or interfaces
in all, a confusing array of classes related to I/O.
In this module we will begin to make some sense of these
classes.
To start with, we will divide the classes into five
categories:
Next, let's focus on the difference between InputStream
and Reader:
We will next look at some of the java.io classes
via examples.
InputStreamReader isr = new InputStreamReader (System.in);
LineNumberReader lnr = new LineNumberReader (isr);
String s = lnr.readLine();
while (s != null) {
// Process s
// Read next line
s = lnr.readLine();
}
Also, a number of classes related to compression and ZIP files
are in the package java.util.zip.
A Reader instance (actually, an instance of
InputStreamReader) can be made to read from an
InputStream and return data at a higher level.
InputStreamReader isr = new InputStreamReader (System.in);
LineNumberReader lnr = new LineNumberReader (isr);
String s = lnr.readLine();
Here:
To get started, let us first write a Producer-Consumer
pair using a buffer:
Here is the code:
(source file)
Note:
The above code will be used as the basis for a number of
examples that follow.
At the end, the output looks like:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class Producer extends Frame {
Label L; // A place to write stuff.
Buffer buf; // Reference to the buffer.
public Producer (Buffer buf)
{
// Store the reference to the buffer.
this.buf = buf;
// Create the frame.
this.setSize (600,100);
this.setLocation (0,100);
this.setTitle ("Producer");
this.setBackground (Color.white);
// this.setLayout (new BorderLayout());
// This is where we will write to.
L = new Label ("");
this.add (L, BorderLayout.CENTER);
this.setVisible (true);
}
public void run ()
{
// Write 25 random bytes to the buffer.
for (int i=1; i<=25; i++) {
// Create a random byte
byte k = (byte) UniformRandom.uniform (1, 100);
// Write to label first.
L.setText (L.getText() + " " + k);
// Write it to the screen.
System.out.println ("Producer: writing " + k);
// Write integer to buffer.
buf.write_byte (k);
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(100,1000));
}
catch (InterruptedException e) {
System.out.println (e);
}
}
buf.write_byte ((byte)-1);
L.setText (L.getText() + " Done!");
}
}
class Consumer extends Frame {
Label L; // Data similar to Producer.
Buffer buf;
public Consumer (Buffer buf)
{
this.buf = buf;
this.setSize (600,100);
this.setLocation (0, 200);
this.setTitle ("Consumer");
this.setBackground (Color.white);
// this.setLayout (new BorderLayout());
L = new Label ("");
this.add (L, BorderLayout.CENTER);
this.setVisible (true);
}
public void run ()
{
// Read byte values until EOF.
while (true) {
// Get the next byte
byte k = buf.read_byte ();
// Check if end-of-data.
if (k < 0) break;
System.out.println ("Consumer: just read " + k);
// Write it on the frame.
L.setText (L.getText() + " " + k);
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(500,1000));
}
catch (InterruptedException e) {
System.out.println (e);
}
}
L.setText (L.getText() + " Done!");
}
}
// A buffer written as a monitor.
class Buffer {
byte[] buf; // The buffer.
int write_cursor = 0; // Current write position.
int read_cursor = 0; // Current read position.
public Buffer ()
{
// Allocate space.
buf = new byte[1000];
}
public void write_byte (byte x)
{
// Write to next available space.
buf [++write_cursor] = x;
}
public byte read_byte ()
{
// Read next byte.
byte k = buf [++read_cursor];
return k;
}
}
// This is an independent quit button to quit the application.
class QuitButton extends Frame {
public QuitButton ()
{
this.setSize (80,50);
this.setLocation (0, 0);
this.setTitle ("Quit button");
Button quitb = new Button ("QUIT");
quitb.setBackground (Color.red);
quitb.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent a)
{
System.exit (0);
}
}
);
this.add (quitb, BorderLayout.CENTER);
this.setVisible (true);
}
}
public class IO1 {
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
// A buffer instance.
Buffer buf = new Buffer ();
// Create a producer instance and run it.
Producer p = new Producer (buf);
p.run();
// Create a consumer instance and run it.
Consumer c = new Consumer (buf);
c.run();
}
}
(We will describe Buffer below).
(In an actual application, presumably each class would be
doing some "work" with the data).
Let us re-write the above sequential version and make it
threaded (concurrent):
The most important change occurs in the class Buffer,
which now needs to permit only synchronized access
to the buffer.
Here is the code for Buffer:
(complete source file)
With this background, we will now look at various I/O streams
in java.io:
class Producer extends Frame implements Runnable {
// ...
}
class Consumer extends Frame implements Runnable {
// ...
}
// Create an independent quit button.
QuitButton q = new QuitButton ();
// A buffer instance.
Buffer buf = new Buffer ();
// Create a producer instance and thread.
Producer p = new Producer (buf);
Thread pthread = new Thread (p);
// Create a consumer instance and thread.
Consumer c = new Consumer (buf);
Thread cthread = new Thread (c);
// Start the threads.
pthread.start();
cthread.start();
class Buffer {
byte[] buf; // The buffer.
int write_cursor = 0; // Pointer to last written entry.
int read_cursor = 0; // Pointer to last read entry.
boolean consumer_waiting =false; // A waiting flag.
public Buffer ()
{
// Allocate space.
buf = new byte[1000];
}
public synchronized void write_byte (byte x)
{
// Write to next available space.
buf [++write_cursor] = x;
// If consumer was waiting, notify.
if (consumer_waiting)
notify ();
}
public synchronized byte read_byte ()
{
// If there isn't enough to read, wait.
if (read_cursor == write_cursor) {
consumer_waiting = true;
try {
wait ();
}
catch (InterruptedException e) {
System.out.println (e);
}
consumer_waiting = false;
}
// Now read next value.
byte k = buf [++read_cursor];
return k;
}
}
Recall that the sequential version above used a buffer
(that we implemented ourselves).
Recall also that the buffer provided access methods that
consisted of writing and reading a byte.
We will now use instances of ByteArrayOutputStream
and ByteArrayInputStream to achieve the same purpose.
Here is the code:
(source file)
Note:
It's hard at this time to see why InputStream's
and OutputStream's are useful. So, let's look at another
example.
class Producer extends Frame {
Label L;
OutputStream out_stream; // For the output.
public Producer (OutputStream out_stream)
{
// Store the reference to the buffer.
this.out_stream = out_stream;
// Create the frame.
this.setSize (600,100);
this.setLocation (0,100);
this.setTitle ("Producer");
this.setBackground (Color.white);
// this.setLayout (new BorderLayout());
// This is where we will write to.
L = new Label ("");
this.add (L, BorderLayout.CENTER);
this.setVisible (true);
}
// Must implement the run() method.
public void run ()
{
// Write 25 random bytes to the buffer.
for (int i=1; i<=25; i++) {
// Create a random byte
byte k = (byte) UniformRandom.uniform (1, 100);
// Write to label first.
L.setText (L.getText() + " " + k);
// Write it to the screen.
System.out.println ("Producer: writing " + k);
// Write integer to buffer.
try {
out_stream.write (k);
}
catch (IOException e) { System.out.println (e); }
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(100,1000));
}
catch (InterruptedException e) { System.out.println (e); }
}
try {
out_stream.write ((byte)-1);
}
catch (IOException e) { System.out.println (e); }
L.setText (L.getText() + " Done!");
}
}
class Consumer extends Frame {
Label L;
InputStream in_stream; // To get data from.
public Consumer (InputStream in_stream)
{
this.in_stream = in_stream;
this.setSize (600,100);
this.setLocation (0, 200);
this.setTitle ("Consumer");
this.setBackground (Color.white);
// this.setLayout (new BorderLayout());
L = new Label ("");
this.add (L, BorderLayout.CENTER);
this.setVisible (true);
}
public void run ()
{
// Read byte values until EOF.
while (true) {
// Get the next byte
int i = -1;
try {
i = in_stream.read ();
}
catch (IOException e) { System.out.println (e); }
byte k = (byte) i;
// Check if end-of-data.
if (k < 0) break;
System.out.println ("Consumer: just read " + k);
// Write it on the frame.
L.setText (L.getText() + " " + k);
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(500,1000));
}
catch (InterruptedException e) { System.out.println (e); }
}
L.setText (L.getText() + " Done!");
}
}
// This is an independent quit button to quit the application.
class QuitButton extends Frame {
// ... as before ...
}
public class IO3 {
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
// Set up an output stream to write into an array.
ByteArrayOutputStream buf_out = new ByteArrayOutputStream (1000);
// Create a producer instance and run it.
Producer p = new Producer (buf_out);
p.run();
// Retrive the array from buf_out.
byte[] buf = buf_out.toByteArray();
// Now wrap an input stream around the array.
ByteArrayInputStream buf_in = new ByteArrayInputStream (buf);
// Create a consumer instance and run it.
Consumer c = new Consumer (buf_in);
c.run();
}
}
class Producer extends Frame {
OutputStream out_stream; // For the output.
public Producer (OutputStream out_stream)
{
// Store the reference to the buffer.
this.out_stream = out_stream;
// ...
}
// ...
}
try {
out_stream.write (k); // k is a byte
}
catch (IOException e) { System.out.println (e); }
(A try-catch block is required).
try {
i = in_stream.read ();
}
catch (IOException e) { System.out.println (e); }
byte k = (byte) i;
Here:
(Recall: an int is four bytes).
byte k = (byte) i;
// Check if end-of-data.
if (k < 0) break;
This has nothing to do with Java - it is simply our own way
of signalling between the Producer and Consumer.
If Java wants to signal "End-of-Data", it will make
the int negative.
// Set up an output stream to write into an array.
ByteArrayOutputStream buf_out = new ByteArrayOutputStream (1000);
Producer p = new Producer (buf_out);
p.run();
// Retrieve the array from buf_out.
byte[] buf = buf_out.toByteArray();
// Now wrap an input stream around the array.
ByteArrayInputStream buf_in = new ByteArrayInputStream (buf);
// Create a consumer instance and run it.
Consumer c = new Consumer (buf_in);
c.run();
Next, instead of having the Producer and Consumer write
and read from a buffer, let's use a file:
Here is (part of) the code:
(source file)
Note:
class Producer extends Frame {
// ...
public Producer (OutputStream out_stream)
{
// ... same as before ...
}
// Must implement the run() method.
public void run ()
{
// ... same as before ...
}
}
class Consumer extends Frame {
// ...
public Consumer (InputStream in_stream)
{
// ... same as before ...
}
public void run ()
{
// ... same as before ...
}
}
class QuitButton extends Frame {
// ... same as before ...
}
public class IO4 {
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
try {
// ByteArrayOutputStream buf_out = new ByteArrayOutputStream (1000);
// Set up a temporary file.
File f = new File ("IO4_temp");
// Create an output stream for it.
FileOutputStream file_out = new FileOutputStream (f);
// Create a producer instance and run it.
// Producer p = new Producer (buf_out);
Producer p = new Producer (file_out);
p.run();
// Close the file so it can be read.
file_out.close ();
// ByteArrayInputStream buf_in = new ByteArrayInputStream (buf);
FileInputStream file_in = new FileInputStream (f);
// Create a consumer instance and run it.
// Consumer c = new Consumer (buf_in);
Consumer c = new Consumer (file_in);
c.run();
file_in.close ();
}
catch (IOException e) { System.out.println (e); }
}
}
(It derives from OutputStream).
(It derives from InputStream).
FileOutputStream file_out = new FileOutputStream (f);
Producer p = new Producer (file_out);
A pipe is really a buffer controlled by
the operating-system (or in Java's case, the library) to enable
communication between processes (or threads).
Fortunately, Java implements pipes and implements them using
streams.
We will now see how easy it is to modify the above code
(communicating via files) to allow the Producer
and Consumer to communicate via pipes:
Here is the main() code:
(complete source file)
Note:
Exercise 13.1
(Solution):
Modify the above code so that the Producer and
Consumer run as threads. (Hint: all your changes
will be in main() only).
// Set up an output pipe.
PipedOutputStream pipe_out = new PipedOutputStream ();
// Set up an input pipe.
PipedInputStream pipe_in = new PipedInputStream (pipe_out);
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
try {
// Set up an output pipe.
PipedOutputStream pipe_out = new PipedOutputStream ();
// Set up an input pipe.
PipedInputStream pipe_in = new PipedInputStream (pipe_out);
// Create a producer instance and run it.
Producer p = new Producer (pipe_out);
p.run();
// Create a consumer instance and run it.
Consumer c = new Consumer (pipe_in);
c.run();
}
catch (IOException e) { System.out.println (e); }
}
Sometimes it is desirable to avoid byte-by-byte processing:
We will now "wrap" a buffer around the pipe and let the
Producer control when the buffer "dumps" its contents
into the pipe:
The code in main() is changed to:
(complete source file)
Note:
Exercise 13.2
(Solution):
Run the above code and observe
what happens: you should see the Consumer read the data in two
bursts.
Modify the above code (only in main())
to remove the use of the BufferedOutputStream.
What do you observe?
public void run ()
{
// Write 25 random bytes to the buffer.
for (int i=1; i<=25; i++) {
// Create a random byte
byte k = (byte) UniformRandom.uniform (1, 100);
// Write to label first.
L.setText (L.getText() + " " + k);
// Write it to the screen.
System.out.println ("Producer: writing " + k);
// Write integer to buffer.
try {
out_stream.write (k);
if (i == 12) out_stream.flush ();
}
catch (IOException e) { System.out.println (e); }
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(100,1000));
} catch (InterruptedException e) { System.out.println (e); }
}
// Write EOF and close output stream.
try {
out_stream.write (-1);
out_stream.close (); // Automatic flush.
}
catch (IOException e) { System.out.println (e); }
L.setText (L.getText() + " Done!");
}
}
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
try {
// Create the matching pipes.
PipedOutputStream pipe_out = new PipedOutputStream ();
PipedInputStream pipe_in = new PipedInputStream (pipe_out);
// Wrap a buffer around the Producer.
BufferedOutputStream buf_out = new BufferedOutputStream (pipe_out);
// Create a producer instance and thread. Pass the buffer in.
Producer p = new Producer (buf_out);
Thread pthread = new Thread (p);
// At this time, all the data is sitting in the buffer.
// Flush it out.
buf_out.flush();
// Create a consumer instance and thread.
Consumer c = new Consumer (pipe_in);
Thread cthread = new Thread (c);
// Start the threads.
pthread.start();
cthread.start();
}
catch (IOException e) { System.out.println (e); }
}
Now we will make our first foray into networking by using
sockets:
First, a small tutorial on sockets:
Java makes the use of sockets easy by wrapping input and
output streams around them.
This means that you don't really need to know how sockets
work - you only need to set up a socket and get its streams.
Here's what we will do in our Producer-Consumer example:
And here is the code for the Consumer:
(source file)
To run the programs:
Exercise 13.3
Try it out - run the programs as indicated above, but change
the port number to your assigned port number.
Note:
About "clients" and "servers":
Exercise 13.4
(
Client-Solution
Server-Solution
):
In this exercise, you will create a "client"
(use this template)
and "server"
(use this template)
pair in which:
Very often, a server needs to handle multiple simultaneous
connections:
Fortunately, it is rather easy to handle multiple connections
now that we know how to create threads.
As an example, let us create a server that reads a single byte
from a client, but can handle as many clients as desired:
Exercise 13.5
(Solution):
In this exercise, you will observe a multi-client server
in action (without actually writing one).
Use the client code in Exercise 13.4 and modify it so that
port number 5010 is used. Then, follow the instructions
given in class.
Let us return to the Producer-Consumer (with sockets) example and
write an applet version:
The code changes are minimal:
The code (Producer code
and Consumer code) is
straightforward and will not be discussed any further.
Now we will look at the class DataOutputStream:
We will use our Producer-Consumer framework to
examine DataOutputStream:
Here's the code:
(source file)
When run, the result produced is:
Note:
You can use DataOutputStream to write data to a file:
Before getting to PrintWriter, let us revisit
the difference between an OutputStream and
a Writer:
The most useful type of Writer is the PrintWriter
class:
Let us now make our Producer write some stuff using a
PrintWriter and examine the byte output with our
hex-reading Consumer:
(source file)
The result produced is:
Note:
The input equivalent of PrintWriter is
LineNumberReader:
We will now write a "Chat" program that uses pipes to
communicate:
(source file)
Note:
Exercise 13.6
(Solution):
Modify the above code so that sockets are used as the
medium of communication. Test your code by using your
assigned port number. Note:
You will need a chat "server" (the one that listens on a port) and
you will need a chat "client" (one that connects to the given port).
Since both are similar, do the following:
It is quite easy to write code to download a page
since the HTTP protocol is a text-based protocol.
We will download Yahoo's homepage with the following
code:
(source file)
Note:
Making a query is as easy as obtaining a page. You just
have to know what to tell the webserver:
Only the "GET" portion of the code needs to change:
(source file)
The GET method of HTTP allows only one line of text to be
sent (to the webserver) as the query.
To allow for more complicated stuff to be sent to the
webserver (such as the entries in a form), the POST method
can be used:
source file)
Note:
In the above code, we explicitly used the machine address
and port number.
A higher-level approach is to specify the URL of the file
directly.
This is possible using the URL class in java.net.
The URL is also useful for extracting the machine name
and port number.
For example:
(source file)
Note:
Since URL's can specify a protocol and since Java handles
FTP, the same code as above can be used for FTP:
(source file)
We will use a FileInputStream to read from a file:
Here is the code:
(source file)
If we are reading at a higher-level (using LineNumberReader),
we use the fact that EOF is signalled when a null is
returned, as the following code shows:
(source file)
(The curious reader might want to see what the file
blah2.txt actually contains).
Exercise 13.7
(Solution):
A FileReader combines the steps of using
a FileInputStream and a InputStreamReader.
Thus, you pass a filename (of a text file) to a FileReader
instance, and wrap a LineNumberReader around the result.
Use this template
to read from the file /home/guest/drum/public/blah3.txt
In many applications, you need to write fixed-size records
into a file.
In the following example:
Here is the code:
(source file)
When run, the output produced is:
The class RandomAccessFile allows you to grab
any byte in any file.
Since access in the middle of the file is not stream-oriented
behavior, this class is a stand-alone class (it is not a stream).
In the example below:
Here is the code:
The package java.util.zip provides classes to:
In the example below, we will read from the gzipped file
blah4.txt.gz.
Here is the code:
(source file)
Note:
In this example, we will read from a JAR file:
Here is the code:
(source file)
Note:
Java has a powerful mechanism that lets you write object
instances directly to a stream.
For example, you can write a Person instance
directly using the writeObject() method of
ObjectOutputStream.
Later, you can read (from the same medium) the Person
instance with code like:
To write or read such instances, the class that you want
to write must implement the Serializable interface:
(source file)
Here, Serializable is a "marker" interface (with
no methods), to indicate to the compiler that you want to allow
reading and writing to streams.
Now, let us create a Producer that writes Person
instances and a Consumer that reads them.
Here is the code for the Producer:
(source file)
We will make the Producer and Consumer communicate over the
net using sockets.
Here is the code for the Consumer:
(source file)
The output (to the screen) at the Producer end is:
Similarly, the output at the Consumer end is:
Note:
We will now return to Applet's and cover some
additional topics.
In the example below, we will look at using the
start() and stop() methods of Applet:
Since the code is quite simple, only the start()
and stop() methods will be shown:
(complete source file)
Note:
AppletContext
is a class in package
java.applet
that allows some limited interaction with the browser.
In the example below, we will use the "context" as follows:
First, here is the HTML file that contains the two
frames. Let's call it
main.html:
Thus,
main_part1.html
will contain the applet and
main_part2.html will
be used for displaying pages:
Next, the applet code:
(source file)
Note:
At this time Java provides limited support for sound:
only .au files are handled.
In the example below (the Dog race), we will add a thread
to provide some sound.
The main loop will be augmented as follows:
Thus, we will build a class called Soundtrack
to handle playing of sound:
Note:
Exercise 13.8:
Try executing the code to see
the result:
(Do NOT use port numbers in this range)
(Please use the port number assigned to you for your
own code).
Here is the code for the Producer:
(source file)
Here are the instructions
to make this happen.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class Producer extends Frame implements Runnable {
// ... same as before ...
}
class QuitButton extends Frame {
// ... same as before ...
}
public class IO7_client {
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
try {
// Open a socket to the server.
// Address: felix.seas.gwu.edu, port 5010.
Socket soc = new Socket ("felix.seas.gwu.edu", 5010);
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Producer as client: attempting connection"
+ " to " + remote_machine);
// Note: server must be fired up first!
// Now create the output stream and hand off to producer.
OutputStream out_stream = soc.getOutputStream ();
// Create a producer instance and thread.
Producer p = new Producer (out_stream);
Thread pthread = new Thread (p);
// Start the threads.
pthread.start();
}
catch (IOException e) { System.out.println (e); }
}
}
class Consumer extends Frame implements Runnable {
// ... same as before ...
}
// ...
public class IO7_server {
public static void main (String[] argv)
{
// Create an independent quit button.
QuitButton q = new QuitButton ();
try {
// Create a listening service for connections
// at the designated port number.
ServerSocket srv = new ServerSocket (5010);
// When a connection is made, get the socket.
// The method accept() blocks until then.
System.out.println ("Consumer as server: waiting for a connection");
Socket soc = srv.accept ();
// At this stage, the connection will have been made.
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Consumer as server: accepted a connection"
+ " from " + remote_machine);
// We are going to listen, so get an InputStream
// and hand it over to the consumer.
InputStream in_stream = soc.getInputStream ();
// Create a consumer instance and thread.
Consumer c = new Consumer (in_stream);
Thread cthread = new Thread (c);
// Start the thread.
cthread.start();
}
catch (IOException e) { System.out.println (e); }
}
}
// Create a listening service for connections
// at the designated port number.
ServerSocket srv = new ServerSocket (5010);
Socket soc = srv.accept ();
// We are going to listen, so get an InputStream
// and hand it over to the consumer.
InputStream in_stream = soc.getInputStream ();
Consumer c = new Consumer (in_stream);
Socket soc = new Socket ("felix.seas.gwu.edu", 5010);
// Now create the output stream and hand off to producer.
OutputStream out_stream = soc.getOutputStream ();
// Create a listening service for connections
// at the designated port number.
ServerSocket srv = new ServerSocket (5010);
// When a connection is made, get the socket.
// The method accept() blocks until then.
System.out.println ("Producer as server: waiting for a connection");
Socket soc = srv.accept ();
// At this stage, the connection will have been made.
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Producer as server: accepted a connection"
+ " from " + remote_machine);
// We are going to write, so get the output stream.
OutputStream out_stream = soc.getOutputStream ();
// Create a producer instance and thread.
Producer p = new Producer (out_stream);
Thread pthread = new Thread (p);
// Start the threads.
pthread.start();
// Open a socket to the server.
// Address: felix.seas.gwu.edu, port 5010.
Socket soc = new Socket ("felix.seas.gwu.edu", 5010);
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Consumer as client: attempting connection"
+ " to " + remote_machine);
// Note: server must be fired up first!
// Now create the input stream for the Consumer.
InputStream in_stream = soc.getInputStream ();
// Create a consumer instance and thread.
Consumer c = new Consumer (in_stream);
Thread cthread = new Thread (c);
// Start the thread.
cthread.start();
Handling connections from multiple clients
// Create a listening service for connections
// at the designated port number.
ServerSocket srv = new ServerSocket (5010);
// When a connection is made, get the socket.
// The method accept() blocks until then.
while (true) {
System.out.println ("MultiClientServer: waiting for a connection");
// Wait for a connection.
Socket soc = srv.accept ();
// Now create an instance of the class that can deal
// with the connection.
IndividualClientServer ics = new IndividualClientServer (soc);
// Create a thread for it.
Thread clienthandler = new Thread (ics);
// Fire off the thread and go back to listening
// for the next connection.
clienthandler.start();
}
ServerSocket srv = new ServerSocket (5010);
class IndividualClientServer implements Runnable {
Socket soc;
public IndividualClientServer (Socket soc)
{
this.soc = soc;
}
public void run ()
{
try {
// At this stage, the connection will have been made.
InetAddress remote_machine = soc.getInetAddress();
// Get the input stream to listen to.
InputStream in_stream = soc.getInputStream();
// Read a byte
int i = in_stream.read ();
byte k = (byte) i;
System.out.println ("IndividualClientServer: accepted a connection"
+ " from " + remote_machine + " BYTE=" + k);
}
catch (IOException e) { System.out.println (e); }
}
}
Producer-Consumer with the Producer as an applet
<html>
<body>
The producer applet:
<applet code="IO9_client.class" width=100 height=100>
This browser does not support Java 1.1
</applet>
</body>
</html>
The class DataOutputStream
public class DataOutputStream extends FilterOutputStream
implements DataOutput {
// Constructor
public DataOutputStream (OutputStream out);
// ...
public final void writeBoolean (boolean b);
public final void writeByte (int i);
public final void writeChars (String s);
public final void writeDouble (double d);
public final void writeInt (int i);
public final void writeUTF (String s);
// ...
}
class Producer extends Frame implements Runnable {
// ...
public void run ()
{
try {
byte separator = 127;
DataOutputStream dos = new DataOutputStream (out_stream);
dos.writeBoolean (true);
out_stream.write (separator);
dos.writeInt (5);
out_stream.write (separator);
dos.writeChars ("ABC");
out_stream.write (separator);
dos.writeUTF ("ABC");
out_stream.write (separator);
dos.writeBytes ("ABC");
out_stream.write (separator);
L.setText ("" + true + ", 5, ABC, ABC, ABC");
}
catch (IOException e) { System.out.println (e); }
// Write EOF and close output stream.
try {
out_stream.write (-1);
out_stream.close ();
}
catch (IOException e) { System.out.println (e); }
L.setText (L.getText() + " Done!");
}
}
class Consumer extends Frame implements Runnable {
// ...
public void run ()
{
// Read byte values until EOF.
while (true) {
// Get the next byte
int i = -1;
try {
i = in_stream.read ();
}
catch (IOException e) { System.out.println (e); }
// Extract byte.
byte k = (byte) i;
// Check if end-of-data.
if ( (i < 0) || (k < 0) ) break;
// Convert to hex.
String hex = Integer.toHexString (k);
System.out.println ("Consumer: just read " + k + " (Hex: " + hex + ")");
// Write it on the frame.
L.setText (L.getText() + " " + hex);
// Sleep for a while.
try {
Thread.sleep ((int)UniformRandom.uniform(5,10));
}
catch (InterruptedException e) { System.out.println (e); }
}
L.setText (L.getText() + " Done!");
try {
in_stream.close ();
}
catch (IOException e) { System.out.println (e); }
}
}
// ...
File f = new File ("output.data");
FileOutputStream fos = new FileOutputStream (f);
DataOutputStream dos = new DataOutputStream (fos);
// Now write to the file, e.g.,
dos.writeInt (5):
The class PrintWriter
(Since a Writer is exclusively for text).
// Suppose out_stream is an OutputStream.
OutputStreamWriter osw = new OutputStreamWriter (out_stream);
osw.write ("ABC");
The final result will be six bytes written to the OutputStream
out_stream.
Depends on where you want to send it! (File, screen, socket, whatever).
public class PrintWriter extends Writer {
public PrintWriter (Writer w);
public PrintWriter (Writer w, boolean flush);
public PrintWriter (OutputStream out);
public PrintWriter (OutputStream out, boolean flush);
}
class Producer extends Frame implements Runnable {
// ...
public void run ()
{
try {
byte separator = 127;
DataOutputStream dos = new DataOutputStream (out_stream);
dos.writeInt (5);
out_stream.write (separator);
dos.writeChars ("ABC");
out_stream.write (separator);
PrintWriter pw = new PrintWriter (out_stream, true);
pw.print (5);
pw.flush ();
out_stream.write (separator);
pw.print ("ABC");
pw.flush ();
out_stream.write (separator);
L.setText ("" + true + ", 5, ABC, 5, ABC");
}
catch (IOException e) { System.out.println (e); }
// ...
}
}
class Consumer extends Frame implements Runnable {
// ...
}
// ...
(Because it knows it is writing to an OutputStream).
Using PrintWriter and LineNumberReader
(Instead you must first create an InputStreamReader).
class ChatClient extends Frame implements Runnable {
OutputStream out_stream; // The streams.
InputStream in_stream;
PrintWriter pw;
TextField tf; // For the user to write in.
Panel message_panel; // To display the conversation.
GridLayout grid_layout;
ScrollPane sc;
public ChatClient (OutputStream out_stream, InputStream in_stream)
{
// Store the stream references and create a PrintWriter
this.out_stream = out_stream;
this.in_stream = in_stream;
pw = new PrintWriter (out_stream, true);
// Create the frame.
this.setSize (400,200);
this.setLocation (0,100);
this.setTitle ("Chat Client");
this.setBackground (Color.white);
// this.setLayout (new BorderLayout());
// This is where messages will be displayed:
grid_layout = new GridLayout (1,1);
message_panel = new Panel (grid_layout);
sc = new ScrollPane ();
sc.add (message_panel);
this.add (sc, BorderLayout.CENTER);
tf = new TextField ();
tf.setForeground (Color.blue);
tf.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent a)
{
if (tf.getText().equalsIgnoreCase ("Bye")) {
try {
ChatClient.this.pw.println ("Bye");
ChatClient.this.out_stream.close ();
ChatClient.this.dispose ();
}
catch (IOException e) { System.out.println (e); }
}
else {
display_text ("ME: " + tf.getText(), Color.blue);
pw.println (tf.getText());
tf.setText("");
}
}
}
);
this.add (tf, BorderLayout.SOUTH);
this.setVisible (true);
}
// Display text on a message panel using Label's.
void display_text (String s, Color c)
{
// Create the label.
Label L = new Label (s);
L.setForeground (c);
// Add to the message panel.
message_panel.add (L);
message_panel.invalidate();
// Increment the layout rows for the next message.
grid_layout.setRows (grid_layout.getRows() + 1);
// Scroll to the bottom.
int height = sc.getViewportSize().height;
sc.setScrollPosition (0, height);
// Re-compute the display.
this.validate();
}
// Must implement the run() method.
public void run ()
{
try {
// Only reading needs to be done here.
InputStreamReader isr = new InputStreamReader (in_stream);
PushbackReader pbr = new PushbackReader (isr);
LineNumberReader lnr = new LineNumberReader (pbr);
// Read line by line.
String s = lnr.readLine();
while (s != null) {
s = s.trim();
display_text ("YOU: " + s, Color.red);
if (s.equalsIgnoreCase ("Bye"))
break;
s = lnr.readLine();
}
in_stream.close ();
}
catch (IOException e) { System.out.println (e); }
}
}
// ...
public class IO12 {
public static void main (String[] argv)
{
// ...
try {
// Create the matching pipes. Note that one pipe
// is given to the constructor of the other.
PipedOutputStream pipe_out1 = new PipedOutputStream ();
PipedInputStream pipe_in1 = new PipedInputStream (pipe_out1);
PipedOutputStream pipe_out2 = new PipedOutputStream ();
PipedInputStream pipe_in2 = new PipedInputStream (pipe_out2);
// Create one client instance and thread.
ChatClient c1 = new ChatClient (pipe_out1, pipe_in2);
Thread c1_thread = new Thread (c1);
// Create another client instance and thread.
ChatClient c2 = new ChatClient (pipe_out2, pipe_in1);
Thread c2_thread = new Thread (c2);
// Start the threads.
c1_thread.start();
c2_thread.start();
}
catch (IOException e) { System.out.println (e); }
}
}
pw = new PrintWriter (out_stream, true);
public void actionPerformed (ActionEvent a)
{
if (tf.getText().equalsIgnoreCase ("Bye")) {
try {
ChatClient.this.pw.println ("Bye");
ChatClient.this.out_stream.close ();
ChatClient.this.dispose ();
}
catch (IOException e) { System.out.println (e); }
}
else {
display_text ("ME: " + tf.getText(), Color.blue);
pw.println (tf.getText());
tf.setText("");
}
}
(Which has no such variable).
ChatClient.this.out_stream.close ();
InputStreamReader isr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (pbr);
The only changes you need to make are in main().
Use this template.
The command line stuff is implemented for you.
HTTP: downloading a web page
public class IO13 {
public static void main (String[] argv)
{
try {
// Open a socket to a known webserver.
Socket soc = new Socket ("www.yahoo.com", 80);
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Connection made to " + remote_machine);
// Now create the output and input streams
OutputStream out_stream = soc.getOutputStream ();
PrintWriter pw = new PrintWriter (out_stream);
InputStream in_stream = soc.getInputStream();
InputStreamReader isr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (isr);
// Ask for the index.html page.
pw.print ("GET index.html /HTTP/1.0\n\n");
pw.flush ();
// Get the page.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
// Close the streams.
pw.close ();
lnr.close ();
soc.close ();
}
catch (IOException e) { System.out.println (e); }
}
}
HTTP: making a query
public class IO14 {
public static void main (String[] argv)
{
// ...
// Make the query.
pw.print ("GET /bin/search?p=java\n\n");
pw.flush ();
// Get the results.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
// ...
}
}
HTTP: making a query using POST
pw.print ("POST /bin/search?\n");
pw.print ("Content-type: plain/text\n");
pw.print ("Content-length: 100\n");
pw.print ("p=java");
pw.print ("\n\n");
pw.flush ();
HTTP: using the URL class
// Create a URL instance.
URL u = new URL ("http://www.yahoo.com/index.html");
System.out.println ("Protocol: " + u.getProtocol());
System.out.println ("Host: " + u.getHost());
System.out.println ("Port: " + u.getPort());
// Note: default port number is -1, but the protocol handler
// knows what to do.
System.out.println ("File: " + u.getFile());
// The openStream method makes the connection.
InputStream in_stream = u.openStream();
// Wrap high-level streams around this.
InputStreamReader isr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (isr);
System.out.println ("Input stream opened");
// Now read the result.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
lnr.close ();
HTTP: using the URL class for FTP
// Create a URL instance.
URL u = new URL ("ftp://sunsite.unc.edu/README");
System.out.println ("Protocol: " + u.getProtocol());
System.out.println ("Host: " + u.getHost());
System.out.println ("Port: " + u.getPort());
// Default port number is -1, but it still works.
System.out.println ("File: " + u.getFile());
// Open a connection.
InputStream in_stream = u.openStream();
// Wrap a LineNumberReader
InputStreamReader isr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (isr);
System.out.println ("Input stream opened");
// Fetch the file.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
lnr.close ();
More about file I/O: handling EOF
// Create a file input stream.
FileInputStream in_stream = new FileInputStream ("blah.txt");
// Read from the file.
int i = in_stream.read();
int count = 1;
while (i >= 0) {
System.out.println ("byte# " + count + ": " + i);
count++;
i = in_stream.read();
}
in_stream.close ();
More about file I/O: handling EOF at a higher-level
// Read from a text file using LineNumberReader
FileInputStream in_stream = new FileInputStream ("blah2.txt");
InputStreamReader osr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (osr);
// EOF is signalled by returning a null string.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
lnr.close ();
More about file I/O: using DataOutputStream to write records
// The familiar Person class.
class Person {
String name;
int age;
public Person (String name, int age)
{
this.age = age;
// Make sure the length is exactly five.
if (name.length() > 5)
this.name = name.substring (0,5);
else {
this.name = name;
for (int i=name.length()+1; i<=5; i++)
this.name = this.name + " ";
}
}
public String toString ()
{
return "Person: name=" + name + ", age=" + age;
}
}
public class IO20 {
public static void main (String[] argv)
{
try {
// Writing using DataInputStream.
FileOutputStream file_out = new FileOutputStream ("Persons.data");
DataOutputStream dos = new DataOutputStream (file_out);
// Create three Person instances.
Person p = new Person ("aaa", 16);
System.out.println ("Write: " + p);
dos.writeChars (p.name);
dos.writeInt (p.age);
p = new Person ("bbbb", 32);
System.out.println ("Write: " + p);
dos.writeChars (p.name);
dos.writeInt (p.age);
p = new Person ("cccccccc", 64);
System.out.println ("Write: " + p);
dos.writeChars (p.name);
dos.writeInt (p.age);
dos.close ();
// First, let's look at the raw data in the file.
FileInputStream fis = new FileInputStream ("Persons.data");
int k = fis.read();
int count = 1;
while (k >= 0) {
byte b = (byte) k;
String hex = Integer.toHexString (b);
System.out.println ("Byte #" + count + ": " + hex);
count ++;
k = fis.read();
}
fis.close();
// Now read in the data.
fis = new FileInputStream ("Persons.data");
DataInputStream dis = new DataInputStream (fis);
char[] name_array = new char[5];
for (int i=0; i<5; i++)
name_array[i] = dis.readChar();
String name = new String (name_array);
int age = dis.readInt();
System.out.println ("Read: name=" + name + ", age=" + age);
name_array = new char[5];
for (int i=0; i<5; i++)
name_array[i] = dis.readChar();
name = new String (name_array);
age = dis.readInt();
System.out.println ("Read: name=" + name + ", age=" + age);
dis.close();
}
catch (IOException e) { System.out.println (e); }
}
}
Write: Person: name=aaa , age=16
Write: Person: name=bbbb , age=32
Write: Person: name=ccccc, age=64
Byte #1: 0
Byte #2: 61
Byte #3: 0
Byte #4: 61
Byte #5: 0
Byte #6: 61
Byte #7: 0
Byte #8: 20
Byte #9: 0
Byte #10: 20
Byte #11: 0
Byte #12: 0
Byte #13: 0
Byte #14: 10
Byte #15: 0
Byte #16: 62
Byte #17: 0
Byte #18: 62
Byte #19: 0
Byte #20: 62
Byte #21: 0
Byte #22: 62
Byte #23: 0
Byte #24: 20
Byte #25: 0
Byte #26: 0
Byte #27: 0
Byte #28: 20
Byte #29: 0
Byte #30: 63
Byte #31: 0
Byte #32: 63
Byte #33: 0
Byte #34: 63
Byte #35: 0
Byte #36: 63
Byte #37: 0
Byte #38: 63
Byte #39: 0
Byte #40: 0
Byte #41: 0
Byte #42: 40
Read: name=aaa , age=16
Read: name=bbbb , age=32
More about file I/O: using RandomAccessFile
File f = new File ("Persons.data");
int len = (int) f.length();
int record_size = len / 3;
System.out.println ("Record size = " + record_size);
// Let's get the second record.
FileInputStream fis = new FileInputStream (f);
DataInputStream dis = new DataInputStream (fis);
dis.skipBytes (record_size);
char[] name_array = new char[5];
for (int i=0; i<5; i++)
name_array[i] = dis.readChar();
String name = new String (name_array);
int age = dis.readInt();
System.out.println ("Read: name=" + name + ", age=" + age);
dis.close();
// Using a RandomAccessFile
RandomAccessFile raf = new RandomAccessFile (f, "rw");
raf.seek (record_size);
name_array = new char[5];
for (int i=0; i<5; i++)
name_array[i] = raf.readChar();
name = new String (name_array);
age = raf.readInt();
System.out.println ("Read: name=" + name + ", age=" + age);
// Writing.
raf.seek (2*record_size);
Person p = new Person ("ddd", 24);
raf.writeChars (p.name);
raf.writeInt (p.age);
// Read again.
raf.seek (2*record_size);
name_array = new char[5];
for (int i=0; i<5; i++)
name_array[i] = raf.readChar();
name = new String (name_array);
age = raf.readInt();
System.out.println ("Read: name=" + name + ", age=" + age);
raf.close();
More about file I/O: reading from a GZIP file
// Wrap the appropriate streams in the right order.
FileInputStream file_stream = new FileInputStream ("blah4.txt.gz");
GZIPInputStream gstream = new GZIPInputStream (file_stream);
InputStreamReader osr = new InputStreamReader (gstream);
LineNumberReader lnr = new LineNumberReader (osr);
// Read.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
lnr.close ();
More about file I/O: reading from a JAR file
// First open the ZIP file.
ZipFile zip_file = new ZipFile ("blah.jar");
// Get an Enumeration of its contents.
Enumeration e = zip_file.entries ();
int count = 1;
// Process one by one.
while (e.hasMoreElements()) {
// Get an element.
ZipEntry zip_entry = (ZipEntry) e.nextElement();
// Get an input stream attached to the entry.
InputStream in_stream = zip_file.getInputStream(zip_entry);
// Wrap high-level reader around the input stream.
InputStreamReader osr = new InputStreamReader (in_stream);
LineNumberReader lnr = new LineNumberReader (osr);
System.out.println ("ZIP ENTRY #" + count + ": " + zip_entry);
// Read.
String s = lnr.readLine ();
while (s != null) {
System.out.println (s);
s = lnr.readLine ();
}
lnr.close ();
count++;
// Repeat.
}
Writing objects to streams and reading them in
ObjectOutputStream oos = new ObjectOutputStream (out_stream);
Person p = new Person ("Murderous Matt", 28);
oos.writeObject (p);
ObjectInputStream ois = new ObjectInputStream (in_stream);
Person p = (Person) ois.readObject();
public class Person implements Serializable {
String name;
int age;
public Person (String name, int age)
{
this.name = name;
this.age = age;
}
public String toString ()
{
return "Person:toString: name=" + name + ", age=" + age;
}
}
class Producer implements Runnable {
OutputStream out_stream;
public Producer (OutputStream out_stream)
{
// Store the reference to the output stream.
this.out_stream = out_stream;
}
// Must implement the run() method.
public void run ()
{
try {
// Get an instance of the object output stream.
ObjectOutputStream oos = new ObjectOutputStream (out_stream);
// Create some Person instances and write them out.
Person p = new Person ("Murderous Matt", 28);
System.out.println (p);
oos.writeObject (p);
p = new Person ("Necromancing Nancy", 33);
System.out.println (p);
oos.writeObject (p);
oos.close ();
}
catch (IOException e) { System.out.println (e); }
}
}
public class IO27_client {
public static void main (String[] argv)
{
try {
// Open a socket to the server.
// Address: felix.seas.gwu.edu, port 5010.
Socket soc = new Socket ("felix.seas.gwu.edu", 5010);
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Producer as client: attempting connection"
+ " to " + remote_machine);
// Note: server must be fired up first!
// Now create the output stream and hand off to producer.
OutputStream out_stream = soc.getOutputStream ();
// Create a producer instance and thread.
Producer p = new Producer (out_stream);
Thread pthread = new Thread (p);
// Start the threads.
pthread.start();
}
catch (IOException e) { System.out.println (e); }
}
}
class Consumer implements Runnable {
InputStream in_stream;
public Consumer (InputStream in_stream)
{
this.in_stream = in_stream;
}
public void run ()
{
try {
// Open an ObjectInputStream.
ObjectInputStream ois = new ObjectInputStream (in_stream);
// Read Person instances from the stream.
Person p = (Person) ois.readObject();
System.out.println (p);
p = (Person) ois.readObject();
System.out.println (p);
ois.close();
}
catch (IOException e) { System.out.println (e); }
catch (ClassNotFoundException e) { System.out.println (e); }
}
}
public class IO27_server {
public static void main (String[] argv)
{
try {
// Create a listening service for connections
// at the designated port number.
ServerSocket srv = new ServerSocket (5010);
// When a connection is made, get the socket.
// The method accept() blocks until then.
System.out.println ("Consumer as server: waiting for a connection");
Socket soc = srv.accept ();
// At this stage, the connection will have been made.
InetAddress remote_machine = soc.getInetAddress();
System.out.println ("Consumer as server: accepted a connection"
+ " from " + remote_machine);
// We are going to listen, so get an InputStream
// and hand it over to the consumer.
InputStream in_stream = soc.getInputStream ();
// Create a consumer instance and thread.
Consumer c = new Consumer (in_stream);
Thread cthread = new Thread (c);
// Start the thread.
cthread.start();
}
catch (IOException e) { System.out.println (e); }
}
}
Producer as client: attempting connection to felix.seas.gwu.edu/128.164.9.3
Person:toString: name=Murderous Matt, age=28
Person:toString: name=Necromancing Nancy, age=33
Consumer as server: waiting for a connection
Consumer as server: accepted a connection from aphid.seas.gwu.edu/128.164.3.88
Person:toString: name=Murderous Matt, age=28
Person:toString: name=Necromancing Nancy, age=33
More about applets: start() and stop() methods
public void stop ()
{
DogGroup.suspend ();
}
public void start ()
{
DogGroup.resume ();
}
More about applets: using the AppletContext
<html>
<body>
<frameset border=2 framespacing=0 frameborder=6 cols="300,*">
<frame name="part1" src="main_part1.html" marginheight=2
marginwidth=2 scrolling="no" noresize>
<frame name="part2" src="main_part2.html" marginheight=2
marginwidth=2 scrolling="yes" noresize>
</frameset>
</body>
</html>
<html>
<body>
Enter the URL of a page you want to see:
<applet code="IO26.class" width=200 height=40>
This browser does not support Java 1.1
</applet>
</body>
</html>
<html>
<body>
</body>
</html>
public class IO26 extends Applet {
TextField tf; // A textfield for the URL.
AppletContext context; // The applet context variable.
public void init ()
{
// We will place the text field inside a colored box.
this.setBackground (Color.pink);
// Create a 20-column text field.
tf = new TextField (20);
tf.setForeground (Color.blue);
tf.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent a)
{
// This method is written below.
display_URL (tf.getText());
}
}
);
this.add (tf);
this.setVisible (true);
// Get the applet context ready.
context = this.getAppletContext();
}
void display_URL (String s)
{
try {
// Parse the URL.
URL u = new URL (s);
// Fetch and display in the second frame.
context.showDocument (u, "part2");
}
catch (MalformedURLException e) { System.out.println (e); }
}
}
Here is the result:
More about applets: playing a sound clip
// Create two dog instances with different ID's.
Dog d1 = new Dog (1, c);
Dog d2 = new Dog (2, c);
// Create a ThreadGroup instance.
DogGroup = new ThreadGroup ("All dogs");
// Create a Thread instance for each dog.
// Note: the class Dog must implement the
// Runnable interface.
Thread d1_thread = new Thread (DogGroup, d1);
Thread d2_thread = new Thread (DogGroup, d2);
Dog.start_race();
// Start running the threads.
// ("start" is a method in Thread).
d1_thread.start();
d2_thread.start();
// Create a sound thread.
Soundtrack strack = new Soundtrack (sound);
Thread sthread = new Thread (DogGroup, strack);
sthread.start();
class Soundtrack implements Runnable {
AudioClip sound;
public Soundtrack (AudioClip sound)
{
this.sound = sound;
}
public void run ()
{
sound.loop();
}
}
// Get audio clip
sound = this.getAudioClip (this.getDocumentBase(), "soundtrack.au");
Here, the assumption is that the clip lies in the same directory
as the HTML document.