Cover | Table of Contents | Colophon
java.io package. For
the most part I/O in Java is divided into two
types: byte- and number-oriented
I/O, which is handled by input and output streams; and
character and text I/O, which is handled
by readers and writers. Both types provide an abstraction for
external data sources and targets that allows you to read from and
write to them, regardless of the exact type of the source. You use
the same methods to read from a file that you do to read from the
console or from a network connection.java.io package proper. (We'll see the
reasons for this design decision later.) Finally, we'll take a
brief look at the Java Communications API
(System.in. Similarly an output stream may have a
definite number of bytes to output or an indefinite number of bytes.System.in
.
This is the same thing as stdin in C, generally
some sort of
console
window, probably the one in which the Java program was launched. If
input is redirected so the program reads from a file, then
System.in is changed as well. For instance, on
Unix, the following command redirects stdin so
that when the MessageServer program reads from
System.in, the actual data comes from the file
data.txt instead of the console:% java MessageServer < data.txt
int
, a four-byte, big-endian, two's
complement integer. An int can take on all values
between -2,147,483,648 and 2,147,483,647. When you type a literal
integer like 7, -8345, or 3000000000 in Java source code, the
compiler treats that literal as an int. In the
case of 3000000000 or similar numbers too large to fit in an
int, the compiler emits an error message citing
"Numeric overflow."longs
are eight-byte, big-endian, two's complement integers with
ranges from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
long literals are indicated by suffixing the
number with a lower- or uppercase L. An
uppercase L is preferred because the lowercase
l is too easily confused with the numeral 1 in
most fonts. For example, 7L, -8345L, and 3000000000L are all 64-bit
long literals.short
and the
byte
.
shorts are two-byte, big-endian, two's
complement integers with ranges from -32,768 to 32,767. They're
rarely used in Java and are included mainly for compatibility with C.bytes, however, are very much used in Java. In
particular they're used in I/O. A byte is an
eight-bit, two's complement integer that ranges from -128 to
127. Note that like all numeric data types in Java, a
byte is signed. The maximum
byte value is 127. 128, 129, and so on through 255
are not legal values for bytes.byte
value between
and 127 from a stream, then cast it to a char, the
result would be the corresponding ASCII character.chars according to a
specified encoding format before passing them along. Similarly,
writers convert chars to bytes according to a
specified encoding before writing them onto some underlying stream.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.
There are nine reader and eight
writer
classes in the core Java API, all in the java.io
package:
BufferedReader
|
BufferedWriter
|
CharArrayReader
|
CharArrayWriter
|
IOException. IOException is a
checked exception, so you must either declare that your methods throw
it or enclose the call that can throw it in a
try/catch block. The only real
exceptions to this rule are the PrintStream and
PrintWriter classes. Because it would be
inconvenient to wrap a
try/catch block around each
call to System.out.println(), Sun decided to have
PrintStream (and later
PrintWriter) catch and eat any exceptions thrown
inside a print() or println()
method. If you do want to check for exceptions inside a
print() or println() method,
you can call
checkError()
:public boolean checkError()
checkError() method returns
true if an exception has occurred on this print
stream, false if one hasn't. It only tells
you that an error occurred. It does not tell you what sort of error
occurred. If you need to know more about the error, you'll have
to use a different output stream or writer class.IOException has many subclasses—15 in
java.io—and methods often throw a more
specific exception that subclasses IOException.
(However, methods usually only declare that they throw an
IOException.) Here are the subclasses of
IOException that you'll find in
System.out
or
System.err
and the default source of input for
System.in
.
On most platforms the console is the command-line environment from
which the Java program was initially launched, perhaps an
xterm (Figure 1.1) or a DOS
shell window (Figure 1.2). The word
console is something of a misnomer, since on
Unix systems the console refers to a very specific command-line
shell, rather than being a generic term for command-line shells
overall.
System.out works but System.in
does not.
Figure 1.3 shows the Mac console window.
java.io.OutputStream
class declares the three basic methods you
need to write bytes of data onto a stream. It also has methods for
closing and flushing streams.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
OutputStream is an abstract class. Subclasses
provide implementations of the abstract write(int
b) method. They may also override the four
nonabstract methods. For example, the
FileOutputStream class overrides all five methods
with native methods that know how to write bytes into files on the
host platform. Although OutputStream is abstract,
often you only need to know that the object you have is an
OutputStream ; the more specific subclass of
OutputStream is hidden from you. For example, the
getOutputStream() method of
java.net.URLConnection has the signature:public OutputStream getOutputStream() throws IOException
URLConnection object, the actual class of the
output stream that's returned may be a
sun.net.TelnetOutputStream , a
sun.net.smtp.SmtpPrintStream , a
sun.net.www.http.KeepAliveStream , or something
else completely. All you know as a programmer, and all you need to
know, is that the object returned is in fact some instance of
OutputStream. That's why the detailed
classes that handle particular kinds of connections are hidden inside
the sun packages.OutputStream. And since methods that are inherited
are not included in the online documentation, it's important to
remember that they're there. For example, the
java.io.DataOutputStream class does not declare a
java.io.OutputStream
class declares the three basic methods you
need to write bytes of data onto a stream. It also has methods for
closing and flushing streams.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
OutputStream is an abstract class. Subclasses
provide implementations of the abstract write(int
b) method. They may also override the four
nonabstract methods. For example, the
FileOutputStream class overrides all five methods
with native methods that know how to write bytes into files on the
host platform. Although OutputStream is abstract,
often you only need to know that the object you have is an
OutputStream ; the more specific subclass of
OutputStream is hidden from you. For example, the
getOutputStream() method of
java.net.URLConnection has the signature:public OutputStream getOutputStream() throws IOException
URLConnection object, the actual class of the
output stream that's returned may be a
sun.net.TelnetOutputStream , a
sun.net.smtp.SmtpPrintStream , a
sun.net.www.http.KeepAliveStream , or something
else completely. All you know as a programmer, and all you need to
know, is that the object returned is in fact some instance of
OutputStream. That's why the detailed
classes that handle particular kinds of connections are hidden inside
the sun packages.OutputStream. And since methods that are inherited
are not included in the online documentation, it's important to
remember that they're there. For example, the
java.io.DataOutputStream class does not declare a
close() method, but you can still call the one it
inherits from its superclass.OutputStream
class is write():public abstract void write(int b) throws IOException
AsciiChart
, is a simple program that writes the
printable ASCII characters (32 to 126) on the console. The console
interprets the numeric values as ASCII characters, not as numbers.
This is a feature of the console, not of the
OutputStream
class or the specific subclass of
which System.out is an instance. The
write() method merely sends a particular bit
pattern to a particular output stream. How that bit pattern is
interpreted depends on what's connected to the other end of the
stream.import java.io.*;
public class AsciiChart {
public static void main(String[] args) {
for (int i = 32; i < 127; i++) {
System.out.write(i);
// break line after every eight characters.
if (i % 8 == 7) System.out.write('\n');
else System.out.write('\t');
}
System.out.write('\n');
}
}
char literals
'\t' and '\n'. The compiler
converts these to the numbers 9 and 10, respectively. When these
numbers are written on the console, the console interprets those
numbers as a tab and a linefeed, respectively. The same effect could
have been achieved by writing the if clause like
this:if (i % 8 == 7) System.out.write(10); else System.out.write(9);
% java AsciiChart
! " # $ % & '
( ) * + , - . /
0 1 2 3 4 5 6 7
8 9 : ; < = > ?
@ A B C D E F G
H I J K L M N O
P Q R S T U V W
X Y Z [ \ ] ^ _
` a b c d e f g
h i j k l m n o
p q r s t u v w
x y z { | } ~
%write() method do this:public void write(byte[] data) throws IOException public void write(byte[] data, int offset, int length) throws IOException
byte array
data. The second writes only the sub-array of
data starting at offset and
continuing for length bytes. For example, the
following code fragment blasts the bytes in a string onto
System.out:String s = "How are streams treating you?"; byte[] data = s.getBytes(); System.out.write(data);
write().import java.io.*;
public class AsciiArray {
public static void main(String[] args) {
byte[] b = new byte[(127-31)*2];
int index = 0;
for (int i = 32; i < 127; i++) {
b[index++] = (byte) i;
// Break line after every eight characters.
if (i % 8 == 7) b[index++] = (byte) '\n';
else b[index++] = (byte) '\t';
}
b[index++] = (byte) '\n';
try {
System.out.write(b);
}
catch (IOException e) { System.err.println(e); }
}
}
flush()
method forces the data to be written whether or not the buffer is
full:public void flush() throws IOException
flush(). (Then sync() method
in the FileDescriptor class, discussed in Chapter 12, can sometimes be used to empty these buffers.) For example,
assuming out is an OutputStream of some sort, you
would call out.flush() to empty the buffers.close()
method:public void close() throws IOException
out is an
OutputStream of some sort, calling
out.close() closes the stream and implicitly
flushes it. Once you have closed an output stream, you can no longer
write to it. Attempting to do so will throw an
IOException.System.out is a
partial exception because as a PrintStream , all
exceptions it throws are eaten. Once you close
System.out, you can't write to it, but
trying to do so won't throw any exceptions. However, your
output will not appear on the console.OutputStream is an abstract class that mainly
describes the operations available with any particular
OutputStream object. Specific
subclasses know how to write bytes to
particular destinations. For instance, a
FileOutputStream uses native code to write data in
files. A ByteArrayOutputStream uses pure Java to
write its output in a potentially expanding byte
array.write() method in OutputStream,
one abstract, two concrete: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
write(int
b) method. They often choose to override the third
variant, write(byte[],
data
int
offset,
int
length), for reasons of
performance. The implementation of the three-argument version of the
write() method in OutputStream
simply invokes write(int
b)
repeatedly; that is:public void write(byte[] data, int offset, int length) throws IOException {
for (int i = offset; i < offset+length; i++) write(data[i]);
}
write() merely
invokes write(data,
0,
data.length); if the three-argument variant has
been overridden, this method will perform reasonably well. However, a
few subclasses may override it anyway.NullOutputStream
that mimics the behavior of
/dev/null on Unix operating systems. Data
written into a null output stream is lost.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.awt.TextArea that can be connected to an
output stream. As data is written onto the stream, it is appended to
the text area in the default character set (generally ISO Latin-1).
(This isn't ideal. Since text areas contain text, a writer
would be a better source for this data; in later chapters I'll
expand on this class to use a writer instead. For now this makes a
neat example.) This subclass is shown in Example 2.4.StreamedTextArea
class. Each
StreamedTextArea component contains a
TextAreaOutputStream object in its
theOutput field. Client programmers access this
object via the getOutputStream() method of the
StreamedTextArea class. The
StreamedTextArea class has five overloaded
constructors that imitate the five constructors in the
java.awt.TextArea class, each taking a different
combination of text, rows, columns, and scrollbar information. The
first four constructors merely pass their arguments and suitable
defaults to the most general fifth constructor using
this(). The fifth constructor calls the most
general superclass constructor, then calls
setEditable(false) to ensure that the user
doesn't change the text while output is streaming into it.TextArea superclass. However, you might want to do
so if you feel a need to change the normal abilities of a text area.
For example, you could include a do-nothing
append() method so that data can only be moved
into the text area via the provided output stream or a
setEditable() method that doesn't allow the
client programmer to make this area editable.package com.macfaq.awt;
import java.awt.*;
import java.io.*;
public class StreamedTextArea extends TextArea {
OutputStream theOutput = new TextAreaOutputStream();
public StreamedTextArea() {
this("", 0, 0, SCROLLBARS_BOTH);
}
public StreamedTextArea(String text) {
this(text, 0, 0, SCROLLBARS_BOTH);
}
public StreamedTextArea(int rows, int columns) {
this("", rows, columns, SCROLLBARS_BOTH);
}
public StreamedTextArea(String text, int rows, int columns) {
this(text, rows, columns, SCROLLBARS_BOTH);
}
public StreamedTextArea(String text, int rows, int columns, int scrollbars) {
super(text, rows, columns, scrollbars);
setEditable(false);
}
public OutputStream getOutputStream() {
return theOutput;
}
class TextAreaOutputStream extends OutputStream {
public synchronized void write(int b) {
// recall that the int should really just be a byte
b &= 0x000000FF;
// must convert byte to a char in order to append it
char c = (char) b;
append(String.valueOf(c));
}
public synchronized void write(byte[] data, int offset, int length) {
append(new String(data, offset, length));
}
}
}The
java.io.InputStream
class is the abstract superclass for all
input streams. It declares the three basic methods needed to read
bytes of data from a stream. It also has methods for closing and
flushing streams, checking how many bytes of data are available to be
read, skipping over input, marking a position in a stream and
resetting back to that position, and determining whether marking and
resetting are supported.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()
InputStream
class is
read()
,
which reads a single unsigned byte of data and returns the integer
value of the unsigned byte. This is a number between
and 255:public abstract int read() throws IOException
System.in input stream and stores them in the
int array data:int[] data = new int[10];
for (int i = 0; i < data.length; i++) {
data[i] = System.in.read();
}
read() is reading a
byte, it returns an int. If you
want to store the raw bytes instead, you can cast the
int to a byte. For example:byte[] b = new byte[10];
for (int i = 0; i < b.length; i++) {
b[i] = (byte) System.in.read();
}
read() method (that is, a byte in
the range -128 to 127 instead of
to 255). As long as you're clear in your mind and your code
about whether you're working with signed or unsigned data, you
won't have any trouble. Signed bytes can be converted back to
The
java.io.InputStream
class is the abstract superclass for all
input streams. It declares the three basic methods needed to read
bytes of data from a stream. It also has methods for closing and
flushing streams, checking how many bytes of data are available to be
read, skipping over input, marking a position in a stream and
resetting back to that position, and determining whether marking and
resetting are supported.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()
InputStream
class is
read()
,
which reads a single unsigned byte of data and returns the integer
value of the unsigned byte. This is a number between
and 255:public abstract int read() throws IOException
System.in input stream and stores them in the
int array data:int[] data = new int[10];
for (int i = 0; i < data.length; i++) {
data[i] = System.in.read();
}
read() is reading a
byte, it returns an int. If you
want to store the raw bytes instead, you can cast the
int to a byte. For example:byte[] b = new byte[10];
for (int i = 0; i < b.length; i++) {
b[i] = (byte) System.in.read();
}
read() method (that is, a byte in
the range -128 to 127 instead of
to 255). As long as you're clear in your mind and your code
about whether you're working with signed or unsigned data, you
won't have any trouble. Signed bytes can be converted back to
ints in the range
to 255 like this:int i = (b >= 0) ? b : 256 + b;
read(), you also have to catch the
IOException that it might throw. As I've
observed, input and output are often subject to problems outside of
your control: disks fail, network cables break, and so on. Therefore,
virtually any I/O method can throw an IOException,
and read() is no exception. You don't get an
IOException if read()
encounters the end of the input stream; in this case, it returns -1.
You use this as a flag to watch for the end of stream. The following
code shows how to catch the IOException and test
for the end of the stream:try {
int[] data = new int[10];
for (int i = 0; i < data.length; i++) {
int datum = System.in.read();
if (datum == -1) break;
data[i] = datum;
}
}
catch (IOException e) {System.err.println("Couldn't read from System.in!");}read() methods
that read chunks of contiguous data into a byte
array. The first variant tries to read enough data to fill the array
data. The second variant tries to read
length bytes of data starting at position
offset into the array data.
Neither of these methods is guaranteed to read as many bytes as they
want. Both methods return the number of bytes actually read, or -1 on
end of stream.public int read(byte[] data) throws IOException public int read(byte[] data, int offset, int length) throws IOException
java.io.InputStream class merely calls the basic
read() method enough times to fill the requested
array or subarray. Thus, reading 10 bytes of data takes 10 times as
long as reading one byte of data. However, most subclasses of
InputStream override these methods with more
efficient methods, perhaps native, that read the data from the
underlying source as a block.System.in, you could write the following code:try {
byte[] b = new byte[10];
System.in.read(b);
}
catch (IOException e) {System.err.println("Couldn't read from System.in!");}
ArrayIndexOutOfBoundsException will be thrown. For
example, the following code loops repeatedly until it either fills
the array or sees the end of stream:InputStream
class's available() method tells you how
many bytes you can read without blocking. It returns
if there's no data available to be read.public int available() throws IOException
try {
byte[] b = new byte[100];
int offset = 0;
while (offset < b.length) {
int a = System.in.available();
int bytesRead = System.in.read(b, offset, a);
if (bytesRead == -1) break; // end of stream
offset += bytesRead;
}
catch (IOException e) {System.err.println("Couldn't read from System.in!");}
available() returns, like this:try {
byte[] b = new byte[System.in.available()];
System.in.read(b);
}
catch (IOException e) {System.err.println("Couldn't read from System.in!");}
available() method in
java.io.InputStream always returns 0. Subclasses
are supposed to override it, but I've seen a few that
don't. You may be able to read more bytes from the underlying
stream without blocking than available() suggests;
you just can't guarantee that you can. If this is a concern,
you can place input in a separate thread so that blocked input
doesn't block the rest of the program.skip()
method that
jumps over a certain number of bytes in the input:public long skip(long bytesToSkip) throws IOException
skip()
is the number of bytes to skip. The return value is the number of
bytes actually skipped, which may be less than
bytesToSkip. -1 is returned if the end of stream
is encountered. Both the argument and return value are
longs, allowing skip() to
handle extremely long input streams. Skipping is often faster than
reading and discarding the data you don't want. For example,
when an input stream is attached to a file, skipping bytes just
requires that an integer called the file pointer be changed, whereas
reading involves copying bytes from the disk into memory. For
example, to skip the next 80 bytes of the input stream
in:try {
long bytesSkipped = 0;
long bytesToSkip = 80;
while (bytesSkipped < bytesToSkip) {
long n = in.skip(bytesToSkip - bytesSkipped);
if (n == -1) break;
bytesSkipped += n;
}
}
catch (IOException e) {System.err.println(e);}
close()
method:public void close() throws IOException
System.in
generally does not need to be closed, for example. However, streams
associated with files and network connections should always be closed
when you're done with them. For example:try {
URL u = new URL("http://www.javasoft.com/");
InputStream in = u.openStream();
// Read from the stream...
in.close();
}
catch (IOException e) {System.err.println(e);}
IOException.<, <<, or
<<= until you've read one too many
characters. It would be useful to be able to back up and reread the
token once you know which token you've read. Compiler design
and other parsing problems provide many more examples, and this need
occurs in other domains as well.java.io.InputStream
class handle marking and resetting: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. If marking
is not supported, reset() throws an
IOException and mark() does
nothing. Assuming the stream does support marking, the
mark() method places a bookmark at the current
position in the stream. You can rewind the stream to this position
later with reset() as long as you haven't
read more than readLimit bytes. There can be only
one mark in the stream at any given time. Marking a second location
erases the first mark.java.io that
always support marking are BufferedInputStream (of
which System.in is an instance) and
ByteArrayInputStream. However, other input
streams, like DataInputStream , may support
marking if they're chained to a buffered input stream first.InputStream
must provide an
implementation of the abstract read()
method. They may also override some of the nonabstract methods. For
example, the default markSupported() method
returns false, mark() does nothing, and
reset() throws an IOException.
Any class that allows marking and resetting must override these three
methods. Furthermore, they may want to override methods that perform
functions like skip() and the other two
read() methods to provide more efficient
implementations.RandomInputStream
that "reads" random bytes
of data. This provides a useful source of unlimited data you can use
in testing. A java.util.Random object provides the
data.package com.macfaq.io;
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;
}
}
read() method returns a random
int in the range of an unsigned byte (0 to 255).
The other two read() methods fill a specified part
of an array with random bytes. They return the number of bytes read
(in this case the number of bytes created).StreamCopier
class that copies data between two
streams as quickly as possible. (I'll reuse this class in later
chapters.) This method reads from the input stream and writes onto
the output stream until the input stream is exhausted. A 256-byte
buffer is used to try to make the reads efficient. A
main() method provides a simple test for this
class by reading from System.in and copying to
System.out.package com.macfaq.io;
import java.io.*;
public class StreamCopier {
public static void main(String[] args) {
try {
}
catch (IOException e) {System.err.println(e);}
}
public static void copy(InputStream in, OutputStream out)
throws IOException {
// Do not allow other threads to read from the input
// or write to the output while copying is taking place
synchronized (in) {
synchronized (out) {
byte[] buffer = new byte[256];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
}
}
}
}
D:\JAVA\ioexamples\03>java com.macfaq.io.StreamCopier
this is a test this is a test 0987654321 0987654321 ^Z
StreamCopier program until the end of each line.
Since I ran this in Windows, the end-of-stream character is Ctrl-Z.
On Unix it would have been Ctrl-D.System.in and System.out. These
are convenient for examples, but in real life, you'll more
commonly attach streams to data sources like files and network
connections. You'll use the
java.io.FileInputStream and
java.io.FileOutputStream classes, which are
concrete subclasses of java.io.InputStream and
java.io.OutputStream, to read
and write files.
FileInputStream
and
FileOutputStream
provide input and output streams that let
you read and write files. We'll discuss these classes in detail
in this chapter; they provide the standard methods for reading and
writing data. What they don't provide is a mechanism for
file-specific operations, like finding out whether a file is readable
or writable. For that, you may want to look forward to Chapter 12, which talks about the File
class itself and the way Java works with files.java.io.FileInputStream is a concrete subclass of
java.io.InputStream. It provides
an input stream connected to a
particular file.public class FileInputStream extends InputStream
FileInputStream
has all the usual methods of input
streams, such as read(),
available(), skip(), and
close(), which are used exactly as they are for any other input
stream.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
read() methods. These, however, just
pass their arguments on to a private native method called
readBytes(), so effectively all these methods are
implemented with native code. (In Java 2,
java.io.FileInputStream is a concrete subclass of
java.io.InputStream. It provides
an input stream connected to a
particular file.public class FileInputStream extends InputStream
FileInputStream
has all the usual methods of input
streams, such as read(),
available(), skip(), and
close(), which are used exactly as they are for any other input
stream.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
read() methods. These, however, just
pass their arguments on to a private native method called
readBytes(), so effectively all these methods are
implemented with native code. (In Java 2,
read(byte[]
data,
int
offset,
int
length) is a native method
that read(byte[]
data)
invokes.)FileInputStream() constructors,
which differ only in how the file to be read is specified:public FileInputStream(String fileName) throws IOException public FileInputStream(File file) throws FileNotFoundException public FileInputStream(FileDescriptor fdObj)
java.io.File object.
The third constructor uses a
java.io.FileDescriptor object. Filenames are
platform-dependent, so hardcoded file names should be avoided where
possible. Using the first constructor violates Sun's rules for
"100% Pure Java" immediately. Therefore, the second two
constructors are much preferred. Nonetheless, the second two will
have to wait until File objects and file
descriptors are discussed in Chapter 12. For now, I
will use only the first.