Java 2 API: java.io
InputStream/OutputStream vs. Reader/Writer
The streams came first, and were byte-oriented classes. In JDK 1.1,
readers/writers were introduced to handle 16 bit unicode character
input. Readers/writers are locale-dependent. There are bridge classes
which allow you to switch between streams and readers/writers.
Basic I/O
Java's io package was designed in a very "object-oriented" way. The
notion was that the actual implementation did not matter. So in Java,
writing to a network socket looks the same as writing to a file, and
writing arabic text looks the same as writing english, at least as far
as the interface is concerned. This is a good thing. Unfortunately, the
Java designers chose not to provide convenience classes to make some
common kinds of i/o easier. Therefore, even simple i/o in Java can be a
bit confusing at first.
To interact with the user at the command line, Java provides the
streams System.in, System.out, and System.err These streams are pointed
to the console by default, but you can redirect them if you like.
However, in advanced applications, logging is not done using System.out
and System.err. Instead there are logging frameworks for this purpose,
e.g. log4j.
Console I/O Example
package
ca.ucalgary.conted.introjava.console;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class ConsoleIO {
public static void main(String[] args) throws
Exception {
BufferedReader reader =
getConsoleReader();
System.out.print("enter
number: ");
int number =
Integer.parseInt(reader.readLine());
for (int i=0; i<20; i++)
System.out.println();
boolean ok = true;
int guess = 0;
while (ok) {
System.out.print("guess number: ");
guess = Integer.parseInt(reader.readLine());
if
(guess == number) {
System.out.println("you guessed it!");
break;
}
System.out.print("wrong guess! continue (y/n)?");
String continuePlaying = reader.readLine();
if
(continuePlaying.toUpperCase().equals("N")) {
System.out.println("better luck next time!");
break;
}
}
System.out.println("game
over!");
System.exit(0);
}
public static BufferedReader getConsoleReader() {
InputStream is = null;
InputStreamReader isReader =
null;
BufferedReader
bufferedReader = null;
try {
is =
System.in;
isReader = new InputStreamReader(is);
bufferedReader = new BufferedReader(isReader);
} catch (Exception e) {
}
return bufferedReader;
}
}
File I/O
File I/O uses the same Stream/Reader/Writer concepts. Again, there is a
FileInputStream/FileOutputStream combination based no file that contain
characters as bytes (ASCII encoding), and there is a UNICODE based
FileReader/FileWriter combination, which supports more advanced kinds
of text. The FileReader/FileWriter encodes the text based on your
Locale. We may discuss this issue which is called Internationalization
in a later part of the course if time permits. It is important to
note
that in Java a File object is not a link to a file on the actual disk.
It is just an object that stores information about a file. You can ask
about the file size, wether such a file does exist on the disk, and you
can ask it to be deleted or created on the disk, but you can't write to
a file directly using just a File object as you can in other
programming languages.
import
java.io.*;
public class Copy {
public static void main(String[] args) throws IOException {
File inputFile = new File("farrago.txt");
File outputFile = new File("outagain.txt");
FileReader in = new FileReader(inputFile);
FileWriter out = new FileWriter(outputFile);
int c;
while ((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
}
}
Serializing Objects
You can use ObjectInputStream and ObjectOutputStream to serialize
objects. In order for Java to be willing to serialize an object, it has
to implement a special interface called Serializable. The following
example uses the Card and WarCardComparator classes listed in the notes
on Collections. In
order to make it work however, you'll need to modify the Card class so
that it implements java.io.Serializable. In other words, change
public class Card {
to
public class Card implements java.io.Serializable
The code below demonstrates how to implement a trivial object database
in Java. The reason it is trivial is that it serializes an entire
collection of objects to a file, and the only way to retrieve the
collection is all at once into memory. Real databases allow you to
retrieve subsets of the total data into memory. Say you've got a
database with a table that contains 30 million records. It is probably
not a good idea to load all 30 million records into RAM when all you
want to do is view a single record (note: even if each record is only
10 bytes in size, 30 million records add up to 300 MB!; not only
would
doing this tax the server, the performance would be awful).
Serialization isn't used primarily for object storage in terms of a
database as in this example. In real life serialization is used in RMI
and EJB to transfer objects across networks (distributed computing),
and for activation and passivation of Enterprise JavaBeans, for example
as part of load balancing or resource management.
package ca.ucalgary.conted.introjava.cardgames.gameofwar
import
java.util.Stack;
import java.io.*;
public class SerializeCollection {
public static
void main(String[] args) throws Exception {
Card fiveHearts = new Card(Card.HEARTS, Card.FIVE, Card.FACE_UP);
Card queenDiamonds = new Card(Card.DIAMONDS, Card.QUEEN, Card.FACE_UP);
Card eightSpades = new Card(Card.SPADES, Card.EIGHT, Card.FACE_UP);
Card tenClubs = new Card(Card.CLUBS, Card.TEN, Card.FACE_UP);
Stack deck = new Stack();
deck.push(fiveHearts);
deck.push(queenDiamonds);
deck.push(eightSpades);
deck.push(tenClubs);
System.out.print("Original deck: ");
System.out.println(deck);
File deckDB = new File("deck.db");
FileOutputStream fos = new FileOutputStream(deckDB);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(deck);
oos.close();
FileInputStream fis = new FileInputStream(deckDB);
ObjectInputStream ois = new ObjectInputStream(fis);
Stack deck2 = (Stack) ois.readObject();
ois.close();
System.out.print("Deck read from database file: ");
System.out.println(deck2);
}
}
Socket I/O
Below is a very trivial socket I/O example demonstrating a simple
EchoServer and an EchoClient program that uses it. As you can see, once
you master the basics of I/O in Java, it is not very hard to apply this
knowledge to many different areas.
import
java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
public static void main(String[] args) throws
Exception {
ServerSocket serverSocket = null;
try {
serverSocket =
new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
System.out.println("server: starting server...");
clientSocket =
serverSocket.accept();
System.out.println("server: established connection with client...");
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
System.out.println("server:
getting input and output streams");
BufferedReader in = new
BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.println("server: got
input");
PrintWriter out = new
PrintWriter(clientSocket.getOutputStream(), true);
System.out.println("server: got
output");
String inputLine, outputLine;
inputLine = in.readLine();
System.out.println("server: got
command: " + inputLine);
outputLine =
processInput(inputLine);
out.println(outputLine);
out.flush();
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
private static String processInput(String inputLine)
{
return "ack: " + inputLine;
}
}
//------------------------------------------------------
import
java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class EchoClient {
public static void main(String[] args) {
EchoClient client = new
EchoClient();
client.sendData();
}
public void sendData() {
String command = "hello
there!";
try {
Socket
connection = new Socket("localhost", 4444);
PrintWriter
out = new PrintWriter(connection.getOutputStream(), true);
BufferedReader
in = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
out.write(command.toString() + "\n");
out.flush();
System.out.println("client: sent command " + command.toString());
String
response = in.readLine();
System.out.println("client: got response = " + response);
} catch(Exception e) {
e.printStackTrace();
}
}
}