Cell Phones
Pagers
Alarm Watches
etc.
and set your notebook's volume to zero
I really wanted to show people two things:
How to read a line of text from the console
How to do without printf()
Formatting numbers as strings and parsing numbers out of strings are separate operations.
Text is not assumed to be ASCII.
The console is assumed to be the least important target for I/O
Threads are used to perform non-blocking I/O
and more...
A sequence of bytes, generally external to the program
The console: System.in
, System.out
, System.err
Files
Network Connections
Java programs: byte array streams, piped streams, etc.
not GUIs
java.io.InputStream
java.io.OutputStream
java.io.Reader
java.io.Writer
From BufferedInputStream BufferedOutputStream ByteArrayInputStream ByteArrayOutputStream DataInputStream DataOutputStream FileInputStream FileOutputStream FilterInputStream FilterOutputStream ObjectInputStream ObjectOutputStream PipedInputStream PipedOutputStream PrintStream PushbackInputStream SequenceInputStream LineNumberInputStream StringBufferInputStreamjava.io
:
From CheckedInputStream CheckedOutputStream InflaterInputStream DeflaterOutputStream GZIPInputStream GZIPOutputStream ZipInputStream ZipOutputStream java.util.zip
:
From JarInputStream JarOutputStream java.util.jar
:
From DigestInputStream DigestOutputStream java.security
:
From CipherInputStream CipherOutputStream javax.crypto
:
Undocumented classes in the sun packages like
sun.net.TelnetInputStream
and
sun.net.TelnetOutputStream
Third party subclasses and subclasses you write yourself
Streams read and write bytes
The byte
data type is signed
Java always promotes bytes to ints before working on them individually.
Many of the methods in the stream classes return or accept as arguments ints in the range of an unsigned byte (0-255).
The default destination for output written to
System.out
or System.err
,
and the default source of input for System.in
.
Converts written bytes to characters
Cannot be put into raw mode
May or may not exist in an applet
import java.io.*;
public class WriteHello {
public static void main(String[] args) throws IOException {
byte[] hello = {72, 101, 108, 108, 111, 32, 87,
111, 114, 108, 100, 33, 10, 13};
System.out.write(hello);
}
}
I/O is extremely limited in applets:
An applet cannot read a file.
An applet cannot write a file.
An applet cannot delete a file.
An applet cannot determine whether a file exists.
An applet cannot make a network connection to most hosts.
An applet cannot accept an incoming connection from an arbitrary host.
Java uses Unicode
char != byte
Most programs and operating systems don't use Unicode
When reading or writing text the text must be converted.
Therefore, reading and writing bytes is not the same as reading and writing text
An OutputStream
sends raw bytes of data to a
target such as the console or a network server.
OutputStream
is an abstract class.
public abstract class OutputStream extends Object
Many methods in the
class library are only specified to return OutputStream
rather than
the more specific subclass so you tend to
use polymorphism.
Many of the methods of
OutputStream
are generally useful. These are:
public abstract void write(int b) throws IOException
public void write(byte[] data) throws IOException
public void write(byte[] data, int offset, int length) throws IOException
public void flush() throws IOException
public void close() throws IOException
The write()
methods send raw bytes of data to whomever is
listening to this stream.
import java.io.*;
public class HelloOutputStream {
public static void main(String[] args) {
String s = "Hello World\r\n";
// Convert s to a byte array
byte[] b = new byte[s.length()];
s.getBytes(0, s.length()-1, b, 0);
try {
System.out.write(b);
System.out.flush();
}
catch (IOException e) {
System.err.println(e);
}
}
}
Sometimes output streams are buffered by the operating system for performance.
The
flush()
method forces the data to be written whether or not the
buffer is full.
This is not the same as the buffering performed by a
BufferedOutputStream
. That buffering is handled by the Java
runtime. This buffering is at the native OS level.
However, a call to flush()
should empty both buffers
The close()
method closes the stream and releases any resources
associated with the stream.
Once the stream is closed attempts to write to it
throw IOException
s.
You must implement
public abstract void write(int b) throws IOException
Expected semantics:
b
is an int between 0 and 255
If b
is not between 0 and 255, then the three high order
bytes of the int
are thrown away.
You may override other methods for performance.
package com.macfaq.io;
import java.io.*;
public class NullOutputStream extends OutputStream {
public void write(int b) {
}
public void write(byte[] data) {
}
public void write(byte[] data, int offset, int length) {
}
}
java.io.InputStream
is an abstract class that
contains the basic methods for reading raw bytes of data from a
stream.
Although InputStream
is abstract,
many methods are only specified to return
an InputStream
, so you'll often have to deal
directly with only the methods declared in this class.
public abstract int read() throws IOException
public int read(byte[] data) throws IOException
public int read(byte[] data, int offset, int length) throws IOException
public long skip(long n) throws IOException
public int available() throws IOException
public void close() throws IOException
public synchronized void mark(int readlimit)
public synchronized void reset() throws IOException
public boolean markSupported()
public abstract int read() throws IOException
Reads a single unsigned byte of data
Returns an int value of between 0 and 255.
Returns -1 on end of stream
May block
import java.io.*;
public class Echo {
public static void main(String[] args) {
echo(System.in);
}
public static void echo(InputStream in) {
try {
while (true) {
// Notice that although a byte is read, an int
// with value between 0 and 255 is returned.
// Then this is converted to an ISO Latin-1 char
// in the same range before being printed.
int i = in.read();
// -1 is returned to indicate the end of stream
if (i == -1) break;
// without the cast a numeric string like "65"
// would be printed instead of the character "A"
char c = (char) i;
System.out.print(c);
}
}
catch (IOException e) {
System.err.println(e);
}
System.out.println();
}
}
It's more efficient to read multiple bytes at a time:
public int read(byte[] data) throws IOException
public int read(byte[] data, int offset, int length) throws IOException
These methods block until there is some data available. Then
they read as many bytes as they can into b
, or
until they've read length
bytes.
Each returns the number of bytes actually read or -1 on end of stream.
The available()
method tests how many bytes are
ready to be read from the stream without blocking.
public int available() throws IOException
import java.io.*;
public class EfficientEcho {
public static void main(String[] args) {
echo(System.in);
}
public static void echo(InputStream in) {
try {
while (true) {
int n = in.available();
if (n > 0) {
byte[] b = new byte[n];
int result = in.read(b);
if (result == -1) break;
String s = new String(b);
System.out.print(s);
} // end if
} // end while
} // end try
catch (IOException e) {
System.err.println(e);
}
}
}
The skip()
method
reads a specified number of bytes and throws them away.
public int skip(long n) throws IOException
An example:
case 171: // lookupswitch
pad = 3 - (position % 4);
dis.skip(pad);
defaultByte = dis.readInt();
int npairs = dis.readInt();
result = position + " lookupswitch " + defaultByte + " " + npairs;
for (int i = 0; i < npairs; i++) {
int newPosition = position + pad + 12 + i*8;
result += "\n" + newPosition + " "
+ dis.readInt() + " " + dis.readInt();
}
The complete program is included in Chapter 5 of my book, Java Secrets, IDG Books, 1997.)
public synchronized void mark(int readlimit)
public synchronized void reset() throws IOException
public boolean markSupported()
markSupported()
method returns
true
if this stream supports marking and
false
if it doesn't.
The
mark()
method places a bookmark in the stream which
you can return to later using the reset()
method.
There can be only one mark()
in the stream at any
given time. Marking a second location erases the first mark.
If
marking is not supported, these methods throw
IOException
s.
The close()
method closes the stream and releases any resources
associated with the stream.
public void close() throws IOException
Once the stream is closed attempts to read from it
throw IOException
s.
You must implement
public abstract int read() throws IOException
You may override others as well
import java.util.*;
import java.io.*;
public class RandomInputStream extends InputStream {
private transient Random generator = new Random();
public int read() {
int result = generator.nextInt() % 256;
if (result < 0) result = -result;
return result;
}
public int read(byte[] data, int offset, int length)
throws IOException {
byte[] temp = new byte[length];
generator.nextBytes(temp);
System.arraycopy(temp, 0, data, offset, length);
return length;
}
public int read(byte[] data) throws IOException {
generator.nextBytes(data);
return data.length;
}
public long skip(long bytesToSkip) throws IOException {
// It's all random so skipping has no effect
return bytesToSkip;
}
}
The java.io.FileOutputStream
class represents an OutputStream
that
writes bytes to a file. It has the following public methods:
public FileOutputStream(String name) throws IOException
public FileOutputStream(String name, boolean append) throws IOException
public FileOutputStream(File file) throws IOException
public FileOutputStream(FileDescriptor fdObj)
public native void write(int b) throws IOException
public void write(byte[] data) throws IOException
public void write(byte[] data, int offset, int length) throws IOException
public native void close() throws IOException
public final FileDescriptor getFD() throws IOException
This example reads user input from System.in
and writes it into
the files specified on the command line.
import java.io.*;
public class MultiType {
public static void main(String[] args) {
FileOutputStream[] fos = new FileOutputStream[args.length];
for (int i = 0; i < args.length; i++) {
try {
fos[i] = new FileOutputStream(args[i]);
}
catch (IOException e) {
System.err.println(e);
}
} // end for
try {
while (true) {
int n = System.in.available();
if (n > 0) {
byte[] b = new byte[n];
int result = System.in.read(b);
if (result == -1) break;
for (int i = 0; i < args.length; i++) {
try {
fos[i].write(b, 0, result);
}
catch (IOException e) {
System.err.println(e);
}
} // end for
} // end if
} // end while
} // end try
catch (IOException e) {
System.err.println(e);
}
for (int i = 0; i < args.length; i++) {
try {
fos[i].close();
}
catch (IOException e) {
System.err.println(e);
}
}
} // end main
}
It's often useful to be able to append data to an existing file rather
than overwriting it. To do this just pass the boolean value true
as the second argument to the FileOutputStream()
constructor.
For example,
FileOutputStream fos = new FileOutputStream("16.html", true);
import java.io.*;
public class Append {
public static void main(String[] args) {
FileOutputStream[] fos = new FileOutputStream[args.length];
for (int i = 0; i < args.length; i++) {
try {
fos[i] = new FileOutputStream(args[i], true);
}
catch (IOException e) {
System.err.println(e);
}
} // end for
try {
while (true) {
int n = System.in.available();
if (n > 0) {
byte[] b = new byte[n];
int result = System.in.read(b);
if (result == -1) break;
for (int i = 0; i < args.length; i++) {
try {
fos[i].write(b, 0, result);
}
catch (IOException e) {
System.err.println(e);
}
} // end for
} // end if
} // end while
} // end try
catch (IOException e) {
System.err.println(e);
}
for (int i = 0; i < args.length; i++) {
try {
fos[i].close();
}
catch (IOException e) {
System.err.println(e);
}
} // end for
} // end main
}
The FileInputStream
class represents an
InputStream
that reads bytes from a file. It has the following public
methods:
public FileInputStream(String filename) throws FileNotFoundException
public FileInputStream(File file) throws FileNotFoundException
public FileInputStream(FileDescriptor fdObj)
public native int read() throws IOException
public int read(byte[] data) throws IOException
public int read(byte[] data, int offset, int length) throws IOException
public native long skip(long n) throws IOException
public native int available() throws IOException
public native void close() throws IOException
public final FileDescriptor getFD() throws IOException
The java.io.FilterInputStream
and
java.io.FilterOutputStream
classes are concrete
subclasses of InputStream
and
OutputStream
that somehow modify data read from an
underlying stream. You rarely use these classes directly, but
their subclasses are extremely important, especially
DataInputStream
and DataOutputStream
.
You connect filter streams to an underlying stream that supplies
the actual bytes of data by passing the original stream to the
filter stream's constructor. For example, to create a new
DataOutputStream
from a
FileOutputStream
you might do this:
FileOutputStream fos = new FileOutputStream("ln.txt");
DataOutputStream dos = new DataOutputStream(fos);
It's not uncommon to combine these into one line like this:
DataOutputStream dos = new DataOutputStream(new FileOutputStream("ln.txt"));
BufferedInputStream
and BufferedOutputStream
DataInputStream
and
DataOutputStream
PrintStream
PushbackInputStream
GZIPInputStream
and GZIPOutputStream
DigestInputStream
and DigestOutputStream
CipherInputStream
and CipherOutputStream
ObjectInputStream
and ObjectOutputStream
You can also create your own subclasses of
FilterInputStream
and
FilterOutputStream
that perform custom
filtering.
The java.io.BufferedInputStream
and
java.io.BufferedOutputStream
classes buffer reads
and writes by first storing the in a buffer (an internal array
of bytes). Then the program reads bytes from the stream without
calling the underlying native method until the buffer is empty.
The data is read from or written into the buffer in blocks;
subsequent accesses go straight to the buffer.
The only real difference to the client between a regular stream and a buffered stream are the constructors:
public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
public BufferedOutputStream(OutputStream out)
public BufferedOutputStream(OutputStream out, int size)
The best size for the buffer is highly platform dependent and generally related to the block size of the disk, at least for file streams. Less than 512 bytes is probably too little and more than 4096 bytes is probably too much. Ideally you want an integral multiple of the block size of the disk. However, you should use smaller buffer sizes for unreliable network connections.
URL u = new URL("http://java.developer.com");
BufferedInputStream bis = new BufferedInputStream(u.openStream(), 256);
The PushbackInputStream
class provides a pushback buffer so a
program can "unread" bytes onto the stream.
The next time data is read from the stream, the "unread" bytes are read.
public void unread(int b) throws IOException
public void unread(byte[] data, int offset, int length) throws IOException
public void unread(byte[] data) throws IOException
By default the buffer is only one byte long, and trying to unread more than that
throws an IOException
. However you can change the default buffer
size with the second constructor:
public PushbackInputStream(InputStream in)
public PushbackInputStream(InputStream in, int size)
public void print(boolean b)
public void print(int i)
public void print(long l)
public void print(float f)
public void print(double d)
public void print(char s[])
public void print(String s)
public void print(Object obj)
public void println()
public void println(boolean x)
public void println(char x)
public void println(int x)
public void println(long x)
public void println(float x)
public void println(double x)
public void println(char x[])
public void println(String x)
public void println(Object x)
This class traps all
IOException
s. However you can test the error status with checkError()
. This returns true
if an error has occurred,
false
otherwise.
public boolean checkError()
Doesn't internationalize properly
Doesn't handle line breaks in a platform independent way.
DataInputStream
and DataOutputStream
read and write primitive Java
data types and Strings in a machine-independent way.
IEEE 754 for floating point data
big-endian format for integer data
modified UTF-8 for Unicode data
DataOutputStream
declares these methods:
public DataOutputStream(OutputStream out)
public synchronized void write(int b) throws IOException
public synchronized void write(byte[] data, int offset, int length)
throws IOException
public final void writeBoolean(boolean b) throws IOException
public final void writeByte(int b) throws IOException
public final void writeShort(int s) throws IOException
public final void writeChar(int c) throws IOException
public final void writeInt(int i) throws IOException
public final void writeFloat(float f) throws IOException
public final void writeDouble(double d) throws IOException
public final void writeBytes(String s) throws IOException
public final void writeChars(String s) throws IOException
public final void writeUTF(String s) throws IOException
public final int size()
public void flush() throws IOException
DataInputStream
has these methods:
public DataInputStream(InputStream in)
public final int read(byte[] input) throws IOException
public final int read(byte[] input, int offset, int length)
throws IOException
public final void readFully(byte[] input) throws IOException
public final void readFully(byte[] input, int offset, int length)
throws IOException
public final int skipBytes(int n) throws IOException
public final boolean readBoolean() throws IOException
public final byte readByte() throws IOException
public final int readUnsignedByte() throws IOException
public final short readShort() throws IOException
public final int readUnsignedShort() throws IOException
public final char readChar() throws IOException
public final int readInt() throws IOException
public final long readLong() throws IOException
public final float readFloat() throws IOException
public final double readDouble() throws IOException
public final String readUTF() throws IOException
public static final String readUTF(DataInput in)
throws IOException
public final String readLine() throws IOException
Doesn't handle non-ASCII character sets well
Makes dangerous assumptions about line endings
import java.io.*;
import java.util.zip.*;
import com.macfaq.io.*;
public class GZipper {
public final static String GZIP_SUFFIX = ".gz";
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
try {
FileInputStream in = new FileInputStream(args[i]);
FileOutputStream fout = new FileOutputStream(args[i] + GZIP_SUFFIX);
GZIPOutputStream out = new GZIPOutputStream(fout);
byte[] buffer = new byte[256];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
out.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
}
import java.io.*;
import java.util.zip.*;
import com.macfaq.io.*;
public class GUnzipper {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].toLowerCase().endsWith(GZipper.GZIP_SUFFIX)) {
try {
FileInputStream fin = new FileInputStream(args[i]);
GZIPInputStream in = new GZIPInputStream(fin);
FileOutputStream out = new FileOutputStream(
args[i].substring(0, args[i].length()-3));
byte[] buffer = new byte[256];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
out.close();
}
catch (IOException e) {
System.err.println(e);
}
}
else {
System.err.println(args[i] + " does not appear to be a gzipped file.");
}
}
}
}
Must override:
public void write(int b) throws IOException
May override other methods as well for performance
package com.macfaq.io;
import java.io.*;
public class TeeOutputStream extends FilterOutputStream {
private OutputStream out1;
private OutputStream out2;
public TeeOutputStream(OutputStream stream1, OutputStream stream2) {
super(stream1);
out1 = stream1;
out2 = stream2;
}
public synchronized void write(int b) throws IOException {
out1.write(b);
out2.write(b);
}
public synchronized void write(byte[] data, int offset, int length)
throws IOException {
out1.write(data, offset, length);
out2.write(data, offset, length);
}
public void flush() throws IOException {
out1.flush();
out2.flush();
}
public void close() throws IOException {
out1.close();
out2.close();
}
}
Must override:
public int read() throws IOException
May override other methods as well for performance
package com.macfaq.io;
import java.io.*;
public class PrintableInputStream extends FilterInputStream {
public PrintableInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int b = in.read();
// printing, ASCII characters
if (b >= 32 && b <= 126) return b;
// carriage return, linefeed, tab, and end of file
else if (b == 10 || b == 13 || b == 9 || b == -1) return b;
// non-printing characters
else return '?';
}
public int read(byte[] data, int offset, int length) throws IOException {
int result = in.read(data, offset, length);
for (int i = offset; i < offset+result; i++) {
// do nothing with the printing characters
// carriage return, linefeed, tab, and end of file
if (data[i] == 10 || data[i] == 13 || data[i] == 9 || data[i] == -1) ;
// non-printing characters
else if (data[i] < 32 || data[i] > 126) data[i] = (byte) '?';
}
return result;
}
}
Java uses Unicode
Unicode can be serialized in a variety of formats
UTF-8
UCS-2
UCS-4
Most files are in still some other encoding
ASCII
Latin-1
MacRoman
etc.
When you read and write text you must pay attention to character sets.
The java.io.Reader
and java.io.Writer
classes are abstract superclasses for classes that read and
write character based data. The subclasses are notable for
handling the conversion between different character sets.
public abstract class Reader extends Object
public abstract class Writer extends Object
The methods of the java.io.Writer
class are
deliberately similar to the methods of the
java.io.OutputStream
class. However rather than
working with bytes, they work with chars.
The basic write()
method writes a single two-byte
character with a value between 0 and 65535. The value is taken
from the two low-order bytes of the argument c
.
public void write(int c) throws IOException
You can also write an array of characters, a sub-array of characters, a String, or a substring.
public void write(char[] text) throws IOException
public abstract void write(char[] text, int offset, int length) throws IOException
public void write(String s) throws IOException
public void write(String s, int offset, int length) throws IOException
Like output streams, writers may be buffered. To force the write
to take place, call flush()
:
public abstract void flush() throws IOException
Finally the close()
method closes the
Writer
and releases any resources associated with
it.
public abstract void close() throws IOException
The java.io.OutputStreamWriter
class connects byte
streams and character streams.
public OutputStreamWriter(OutputStream out, String enc)
throws UnsupportedEncodingException
public OutputStreamWriter(OutputStream out)
For example, if you wanted to write a file encoded in the Macintosh Symbol font, you might do this:
FileOutputStream fout = new FileOutputStream("symbol.txt");
OutputStreamWriter osw = new OutputStreamWriter(fout, "MacSymbol");
The other methods just override methods from java.io.Writer
, but behave
identically from the perspective of the programmer.
public void write(int c) throws IOException
public void write(char c[], int offset, int length) throws IOException
public void write(String s, int offset, int length) throws IOException
public void flush() throws IOException
public void close() throws IOException
The methods of the java.io.Reader
class
are deliberately similar to the methods of the java.io.InputStream
class.
The basic read()
method reads a single character
(which may may take between one and four bytes depending on the character set)
and returns the character as an int between 0 and 65535.
It returns -1 if the end of stream is seen.
public int read() throws IOException
You can also read many characters into an array of chars.
public int read(char[] text) throws IOException
public abstract int read(char[] text, int offset, int length)
throws IOException
All the read()
methods block until some input is
available, an I/O error occurs, or the end of the stream is reached.
You can skip a certain number of characters.
public long skip(long n) throws IOException
The ready()
method returns true if the reader is
ready to be read from, false if it isn't.
public boolean ready() throws IOException
Readers may or may not support marking and resetting, like input streams.
public boolean markSupported()
public void mark(int readAheadLimit) throws IOException
public void reset() throws IOException
Finally the close()
method closes the
Reader
and releases any resources associated with
it.
public abstract void close() throws IOException
The java.io.InputStreamReader
class serves as a
bridge between byte streams and character streams: It reads
bytes from the input stream and translates them into characters
according to a specified character encoding.
The encoding can be set in the constructor, or you can accept the platform's default encoding.
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String encoding)
throws UnsupportedEncodingException
For example, if you wanted to read a file that had been encoded using the Macintosh Symbol font, you might do this:
FileInputStream fin = new FileInputStream("symbol.txt");
InputStreamReader reader = new InputStreamReader(fin, "MacSymbol");
The other methods just override methods from java.io.Reader
,
but behave identically from the perspective of the programmer:
public int read() throws IOException
public int read(char c[], int off, int length) throws IOException
public boolean ready() throws IOException
public void close() throws IOException
BufferedReader
BufferedWriter
CharArrayReader
CharArrayWriter
FileReader
FileWriter
FilterReader
FilterWriter
InputStreamReader
LineNumberReader
PipedReader
PipedWriter
PrintWriter
PushbackReader
StringReader
StringWriter
A subclass of
java.io.Writer
allows you to use the familiar
print()
and println()
methods
Can be chained to an OutputStreamWriter
to handle non-default character
sets properly.
Automatic flushing is performed only when println()
is invoked, not every time a newline character is seen.
println()
is still dangerous
PrintStream
is unofficially deprecated
public PrintWriter(Writer out)
public PrintWriter(Writer out, boolean autoFlush)
public PrintWriter(OutputStream out)
public PrintWriter(OutputStream out, boolean autoFlush)
public void flush()
public void close()
public boolean checkError()
protected void setError()
public void write(int c)
public void write(char buf[], int offset, int length)
public void write(char buf[])
public void write(String s,
public void write(String s)
public void print(boolean b)
public void print(char c)
public void print(int i)
public void print(long l)
public void print(float f)
public void print(double d)
public void print(char s[])
public void print(String s)
public void print(Object obj)
public void println()
public void println(boolean x)
public void println(char x)
public void println(int x)
public void println(long x)
public void println(float x)
public void println(double x)
public void println(char x[])
public void println(String x)
public void println(Object x)
A subclass of
java.io.Reader
that you chain to another Reader
class to
buffer characters.
Constructor can specify buffer size
public BufferedReader(Reader in, int bufferSize)
public BufferedReader(Reader in)
Also notable for its readLine()
method
that allows you to read text a line at a time.
public String readLine() throws IOException
readLine()
is still evil!
BufferedReader
s do support marking and resetting, at least
up to the
length of the buffer.
// Implement the Unix cat utility in java
import java.io.*;
class cat {
public static void main (String args[]) {
String thisLine;
//Loop across the arguments
for (int i=0; i < args.length; i++) {
//Open the file for reading
try {
BufferedReader br = new BufferedReader(new FileReader(args[i]));
while ((thisLine = br.readLine()) != null) { // while loop begins here
System.out.println(thisLine);
} // end while
} // end try
catch (IOException e) {
System.err.println("Error: " + e);
}
} // end for
} // end main
}
Very much like FilterInputStream
and FilterOutputStream
You must override the three-args read and write methods:
public int read(char[] text, int offset, int length) throws IOException
public void write(char[] text, int offset, int length) throws IOException
C:
scanf("%d", &x);
C++:
cin >> x;
Pascal:
READLN (X);
Fortran:
READ 2, X
2 FORMAT (F5.1)
C:
printf("%.2d", salary);
C++:
cout.precision(2);
cout << salary;
Fortran:
PRINT 20, SALARY
20 FORMAT(F10.2)
I/O is not at all the same thing as converting a number to a string
First convert the number to a string
Then output the string
Much more flexible
java.util.Locale
objects encapsulate differences between
different cultures, languages, and countries
Predefined locales:
Locale.SIMPLIFIED_CHINESE
Locale.CHINA
Locale.PRC
Locale.TRADITIONAL_CHINESE
Locale.TAIWAN
Locale.CANADA
Locale.UK
Locale.US
Locale.FRANCE
Locale.CANADA_FRENCH
Locale.GERMANY
Locale.ITALY
Locale.JAPAN
Locale.KOREA
Locale.ENGLISH
Locale.FRENCH
Locale.GERMAN
Locale.ITALIAN
Locale.JAPANESE
Locale.KOREAN
Locale.CHINESE
Number formats are locale specific
Number formats specify
maximum and minimum integer width
maximum and minimum fraction width (precision, number of decimal places)
whether or not digits are grouped (e.g. 2,109,356 vs. 2109356)
what character digits are grouped with
decimal separator
NumberFormat myFormat = NumberFormat.getInstance();
NumberFormat canadaFormat = NumberFormat.getInstance(Locale.CANADA);
Locale turkey = new Locale("tr", "");
NumberFormat turkishFormat = NumberFormat.getInstance(turkey);
Locale swissItalian = new Locale("it", "CH");
NumberFormat swissItalianFormat = NumberFormat.getInstance(swissItalian);
A NumberFormat
object converts integers and floating
point numbers using one of NumberFormat
's five overloaded
format()
methods:
public final String format(long number)
public final String format(double number)
public abstract StringBuffer format(long number, StringBuffer toAppendTo,
FieldPosition pos)
public abstract StringBuffer format(double number, StringBuffer toAppendTo,
FieldPosition pos)
public final StringBuffer format(Object number, StringBuffer toAppendTo,
FieldPosition pos)
import java.text.*;
public class FormatTest {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getInstance();
for (double x = Math.PI; x < 100000; x *= 10) {
String formattedNumber = nf.format(x);
System.out.println(formattedNumber + "\t" + x);
}
}
}
3.141 3.14159265358979
31.415 31.4159265358979
314.159 314.159265358979
3,141.592 3141.5926535897897
31,415.926 31415.926535897896
3,141 3.14159265358979
31,415 31.4159265358979
314,159 314.159265358979
3 141,592 3141.5926535897897
31 415,926 31415.926535897896
You specify the minimum and maximum of each type you want in each number using these four methods:
public void setMaximumIntegerDigits(int newValue)
public void setMinimumIntegerDigits(int newValue)
public void setMaximumFractionDigits(int newValue)
public void setMinimumFractionDigits(int newValue)
For example, to specify that myFormat
should format
numbers with at least 10 digits before the decimal point and at most
3 digits after, you would type:
myFormat.setMinimumIntegerDigits(10);
myFormat.setMaximumFractionDigits(3);
import java.text.*;
public class PrettyTable {
public static void main(String[] args) {
System.out.println("Degrees Radians Grads");
NumberFormat myFormat = NumberFormat.getInstance();
myFormat.setMinimumIntegerDigits(3);
myFormat.setMaximumFractionDigits(2);
myFormat.setMinimumFractionDigits(2);
for (double degrees = 0.0; degrees < 360.0; degrees++) {
String radianString = myFormat.format(Math.PI * degrees / 180.0);
String gradString = myFormat.format(400 * degrees / 360);
String degreeString = myFormat.format(degrees);
System.out.println(degreeString + " " + radianString
+ " " + gradString);
}
}
}
Output:
300.00 005.23 333.33
301.00 005.25 334.44
302.00 005.27 335.55
303.00 005.28 336.66
304.00 005.30 337.77
305.00 005.32 338.88
306.00 005.34 340.00
307.00 005.35 341.11
308.00 005.37 342.22
309.00 005.39 343.33
310.00 005.41 344.44
311.00 005.42 345.55
312.00 005.44 346.66
313.00 005.46 347.77
314.00 005.48 348.88
Most number formats support grouping and some use it by default.
Ask whether a particular NumberFormat
groups with the isGroupingUsed()
method:
public boolean isGroupingUsed()
You can turn grouping on or off for a number format with the
setGroupingUsed()
method.
public void setGroupingUsed(boolean groupNumbers)
If you know you're going to be working with money, you can request a
currency formatter with the static
NumberFormat.getCurrencyInstance()
method:
public static final NumberFormat getCurrencyInstance()
public static NumberFormat getCurrencyInstance(Locale inLocale)
import java.text.*;
import java.util.*;
public class MinimumWage {
public static void main(String[] args) {
NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(Locale.ENGLISH);
double minimumWage = 5.15;
System.out.println("The minimum wage is "
+ dollarFormat.format(minimumWage));
System.out.println("A worker earning minimum wage and working for forty");
System.out.println("hours a week, 52 weeks a year, would earn "
+ dollarFormat.format(40*52*minimumWage));
}
}
This program prints
The minimum wage is $5.15
A worker earning minimum wage and working for forty
hours a week, 52 weeks a year, would earn $10,712.00
Number formats are also responsible for converting strings to binary numbers.
Number formats provide more flexible conversions than
you can achieve with the methods in the type wrapper classes like
Integer.parseInt()
.
For instance, a percent format parse()
method
can interpret 57% as 0.57 instead of 57.
A currency format can read (12.45) as -12.45.
Understand grouping
public Number parse(String text) throws ParseException
public abstract Number parse(String text, ParsePosition parsePosition)
public final Object parseObject(String source, ParsePosition parsePosition)
import java.text.*;
import java.io.*;
public class RootFinder {
public static void main(String[] args) {
Number input = null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
NumberFormat nf = NumberFormat.getInstance();
while (true) {
System.out.println("Enter a number (-1 to quit): ");
String s = br.readLine();
try {
input = nf.parse(s);
}
catch (ParseException e) {
System.out.println(s + " is not a number I understand.");
continue;
}
double d = input.doubleValue();
if (d < 0) break;
double root = Math.sqrt(d);
System.out.println("The square root of " + s + " is " + root);
}
}
catch (IOException e) {
System.err.println(e);
}
}
}
% java RootFinder Enter a number (-1 to quit): 87 The square root of 87 is 9.327379053088816 Enter a number (-1 to quit): 65.4 The square root of 65.4 is 8.087026647662292 Enter a number (-1 to quit): 3.151592 The square root of 3.151592 is 1.7752723734683644 Enter a number (-1 to quit): 2,345,678 The square root of 2,345,678 is 1531.5606419596973 Enter a number (-1 to quit): 2.998E+8 The square root of 2.998E+8 is 1.7314733610425546 Enter a number (-1 to quit): 299800000 The square root of 299800000 is 17314.733610425545 Enter a number (-1 to quit): 0.0 The square root of 0.0 is 0.0 Enter a number (-1 to quit): four four is not a number I understand. Enter a number (-1 to quit): 4 The square root of 4 is 2.0 Enter a number (-1 to quit): Enter a number (-1 to quit): (12) (12) is not a number I understand. -1
Scientific and engineering notation like 2.998E10, 6.022E23, 931.494013E6, 1.67262158E-27
Only supported in Java 1.3 and later; and then only by affixing E0
to the DecimalFormatSymbols
pattern
In Java 1.2 and earlier, you can roll your own by
subclassing NumberFormat
IBM alphaWorks NumberFormat
class at
http://www.alphaworks.ibm.com/tech/numberformat
Memory mapped I/O
Asynchronous I/O
Direct access to character converter classes
Better support for regular expressions
USB API
Java I/O
Elliotte Rusty Harold
O'Reilly & Associates, 1999
ISBN: 01-56592-485-1
This presentation: http://www.ibiblio.org/javafaq/slides/intljava/2001ny/javaio/