Until now, most of the examples in this book have used the streams
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
, t
o 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
These methods are all implemented in native code, except for the two
multibyte 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.)
There are three 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)
The first constructor uses a string containing the name of the file.
The second constructor uses a 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.
To read a file, just pass the name of the file into the
FileInputStream()
constructor. Then use the
read()
method as normal. For example, the
following code fragment reads the file
README.TXT, then prints it on
System.out
:
try { FileInputStream fis = new FileInputStream("README.TXT"); int n; while ((n = fis.available()) > 0) { byte[] b = new byte[n]; int result = fis.read(b); if (result == -1) break; String s = new String(b); System.out.print(s); } // End while } // End try catch (IOException e) {System.err.println(e);} System.out.println();
Java looks for files in the current working directory. Generally, this is the directory you were in
when you typed java
program_name
to start running the program.
You can open a file in a different directory by passing a full or
relative path to the file from the current working directory. For
example, to read the file /etc/hosts
no matter
which directory is current, you can do this:
FileInputStream fis = new FileInputStream("/etc/hosts");
Notice that this code depends on Unix-style pathnames. It is not guaranteed to work on Windows or the Mac, though it might; some runtime environments like Apple’s Macintosh Runtime for Java include extra code to translate from Unix-style filenames to the native style.
If the file you’re trying to read does not exist when the
FileInputStream
object is constructed, a
FileNotFoundException
(a subclass of
java.io.IOException
) is thrown. If for some other
reason a file cannot be read—for example, the current process
does not have read permission for the file—some other kind of
IOException
is thrown.
Example 4.1
reads filenames from the command
line, then copies the named files onto System.out
.
The StreamCopier.copy()
method from Example 3.3 in the last chapter does the actual reading
and writing. Notice that that method does not care that the input is
coming from a file or going to the console. It works regardless of
the type of the input and output streams it’s copying. It will
work equally well for other streams still to be introduced, including
ones that did not even exist when StreamCopier
was
created.
Example 4-1. The FileTyper Program
import java.io.*; import com.macfaq.io.*; public class FileTyper { public static void main(String[] args) { if (args.length == 0) { System.err.println("Usage: java FileTyper file1 file2 ..."); return; } for (int i = 0; i < args.length; i++) { try { typeFile(args[i]); if (i+1 < args.length) { // more files to type System.out.println(); System.out.println("------------------------------------"); } } catch (IOException e) {System.err.println(e);} } } public static void typeFile(String filename) throws IOException { FileInputStream fin = new FileInputStream(filename); StreamCopier.copy(fin, System.out); fin.close(); } }
Untrusted applets are not usually allowed to read or write files. If
your applet tries to create a FileInputStream
,
the constructor will throw a SecurityException
.
The FileInputStream
class has one method
that’s not declared in the InputStream
superclass, getFD()
.
public final FileDescriptor getFD() throws IOException
This method returns the java.io.FileDescriptor
object associated with this stream. File descriptor objects are
discussed in Chapter 12. For now, all you can do
with this object is use it to create another file stream.
FileInputStream
also has a protected
finalize()
method that’s invoked when a
FileInputStream
object is garbage collected. This
method ensures that files are properly closed before the file input
stream that opened them is garbage-collected:
protected void finalize() throws IOException
You don’t normally need to invoke this method explicitly, but
if you subclass FileInputStrea
m (something
I’ve never found a need for), you must invoke
super.finalize()
from your subclass’s
finalize()
method.
It is possible to open multiple input streams to the same file at the same time, though it’s rarely necessary to do so. Each stream maintains a separate pointer to the current position in the file. Reading from the file does not change the file in any way. Writing to a file is a different story, as you’ll see in the next section.
Get Java I/O now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.