5.9. Input/Output with java.io
The
java.io package defines a large number of
classes for reading and writing streaming, or sequential, data. The
InputStream and OutputStream
classes are for reading and writing streams of bytes while the
Reader and Writer classes are
for reading and writing streams of
characters. Streams can be
nested, meaning you might read characters from a
FilterReader object that reads and processes
characters from an underlying Reader stream. This
underlying Reader stream might read bytes from an
InputStream and convert them to characters.
5.9.1. Reading Console Input
You
can perform a number of common
operations with streams. One is to read lines of input the user types
at the console:
import java.io.*;
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.print("What is your name: ");
String name = null;
try {
name = console.readLine();
}
catch (IOException e) { name = "<" + e + ">"; } // This should never happen
System.out.println("Hello " + name);
5.9.2. Reading Lines from a Text File
Reading lines of text
from a file is a similar operation. The following code reads an
entire text file and quits when it reaches the end:
String filename = System.getProperty("user.home") + File.separator + ".cshrc";
try {
BufferedReader in = new BufferedReader(new FileReader(filename));
String line;
while((line = in.readLine()) != null) { // Read line, check for end-of-file
System.out.println(line); // Print the line
}
in.close(); // Always close a stream when you are done with it
}
catch (IOException e) {
// Handle FileNotFoundException, etc. here
}
5.9.3. Writing Text to a File
Throughout this book,
you've seen the use of the
System.out.println() method to
display text on the console.
System.out simply refers to an output stream. You
can print text to any output stream using similar techniques. The
following code shows how to output text to a file:
try {
File f = new File(homedir, ".config");
PrintWriter out = new PrintWriter(new FileWriter(f));
out.println("## Automatically generated config file. DO NOT EDIT!");
out.close(); // We're done writing
}
catch (IOException e) { /* Handle exceptions */ }
5.9.4. Reading a Binary File
Not all files contain
text, however. The following lines of code treat a file as a stream
of bytes and read the bytes into a large array:
try {
File f; // File to read; initialized elsewhere
int filesize = (int) f.length(); // Figure out the file size
byte[] data = new byte[filesize]; // Create an array that is big enough
// Create a stream to read the file
DataInputStream in = new DataInputStream(new FileInputStream(f));
in.readFully(data); // Read file contents into array
in.close();
}
catch (IOException e) { /* Handle exceptions */ }
5.9.5. Compressing Data
Various
other
packages of the Java
platform define specialized stream classes that operate on streaming
data in some useful way. The following code shows how to use stream
classes from java.util.zip to compute a checksum
of data and then compress the data while writing it to a file:
import java.io.*;
import java.util.zip.*;
try {
File f; // File to write to; initialized elsewhere
byte[] data; // Data to write; initialized elsewhere
Checksum check = new Adler32(); // An object to compute a simple checksum
// Create a stream that writes bytes to the file f
FileOutputStream fos = new FileOutputStream(f);
// Create a stream that compresses bytes and writes them to fos
GZIPOutputStream gzos = new GZIPOutputStream(fos);
// Create a stream that computes a checksum on the bytes it writes to gzos
CheckedOutputStream cos = new CheckedOutputStream(gzos, check);
cos.write(data); // Now write the data to the nested streams
cos.close(); // Close down the nested chain of streams
long sum = check.getValue(); // Obtain the computed checksum
}
catch (IOException e) { /* Handle exceptions */ }
5.9.6. Reading ZIP Files
The java.util.zip
package also contains a ZipFile
class that gives you random access to the entries of a ZIP archive
and allows you to read those entries through a stream:
import java.io.*;
import java.util.zip.*;
String filename; // File to read; initialized elsewhere
String entryname; // Entry to read from the ZIP file; initialized elsewhere
ZipFile zipfile = new ZipFile(filename); // Open the ZIP file
ZipEntry entry = zipfile.getEntry(entryname); // Get one entry
InputStream in = zipfile.getInputStream(entry); // A stream to read the entry
BufferedInputStream bis = new BufferedInputStream(in); // Improves efficiency
// Now read bytes from bis...
// Print out contents of the ZIP file
for(java.util.Enumeration e = zipfile.entries(); e.hasMoreElements();) {
ZipEntry zipentry = (ZipEntry) e.nextElement();
System.out.println(zipentry.getName());
}
5.9.7. Computing Message Digests
If you need to compute a
cryptographic-strength checksum (also known as a message digest), use
one of the stream classes of the java.security
package. For example:
import java.io.*;
import java.security.*;
import java.util.*;
File f; // File to read and compute digest on; initialized elsewhere
List text = new ArrayList(); // We'll store the lines of text here
// Get an object that can compute an SHA message digest
MessageDigest digester = MessageDigest.getInstance("SHA");
// A stream to read bytes from the file f
FileInputStream fis = new FileInputStream(f);
// A stream that reads bytes from fis and computes an SHA message digest
DigestInputStream dis = new DigestInputStream(fis, digester);
// A stream that reads bytes from dis and converts them to characters
InputStreamReader isr = new InputStreamReader(dis);
// A stream that can read a line at a time
BufferedReader br = new BufferedReader(isr);
// Now read lines from the stream
for(String line; (line = br.readLine()) != null; text.add(line)) ;
// Close the streams
br.close();
// Get the message digest
byte[] digest = digester.digest();
5.9.8. Streaming Data to and from Arrays
So far,
we've used a variety of stream classes to manipulate
streaming data, but the data itself ultimately comes from a file or
is written to the console. The java.io package
defines other stream classes that can read data from and write data
to arrays of bytes or strings of text:
import java.io.*;
// Set up a stream that uses a byte array as its destination
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
out.writeUTF("hello"); // Write some string data out as bytes
out.writeDouble(Math.PI); // Write a floating-point value out as bytes
byte[] data = baos.toByteArray(); // Get the array of bytes we've written
out.close(); // Close the streams
// Set up a stream to read characters from a string
Reader in = new StringReader("Now is the time!");
// Read characters from it until we reach the end
int c;
while((c = in.read()) != -1) System.out.print((char) c);
Other classes that operate this way include
ByteArrayInputStream,
StringWriter, CharArrayReader,
and CharArrayWriter.
5.9.9. Thread Communication with Pipes
PipedInputStream and
PipedOutputStream and their character-based
counterparts, PipedReader and
PipedWriter, are another interesting set of
streams defined by java.io. These streams are used
in pairs by two threads that want to communicate. One thread writes
bytes to a PipedOutputStream or characters to a
PipedWriter, and another thread reads bytes or
characters from the corresponding PipedInputStream
or PipedReader:
// A pair of connected piped I/O streams forms a pipe. One thread writes
// bytes to the PipedOutputStream, and another thread reads them from the
// corresponding PipedInputStream. Or use PipedWriter/PipedReader for chars.
final PipedOutputStream writeEndOfPipe = new PipedOutputStream();
final PipedInputStream readEndOfPipe = new PipedInputStream(writeEndOfPipe);
// This thread reads bytes from the pipe and discards them
Thread devnull = new Thread(new Runnable() {
public void run() {
try { while(readEndOfPipe.read() != -1); }
catch (IOException e) {} // ignore it
}
});
devnull.start();
|