Typical uses of IO streams

Bruce Eckel’s Thinking in Java Contents | Prev | Next

Although
there are a lot of IO stream classes in the library that can be combined in
many different ways, there are just a few ways that you’ll probably end
up using them. However, they require attention to get the correct combinations.
The following rather long example shows the creation and use of typical
IO configurations so you can use it as a reference when writing your own code.
Note that each configuration begins with a commented number and title that
corresponds to the heading for the appropriate explanation that follows in the
text.

//: IOStreamDemo.java
// Typical IO Stream Configurations
import java.io.*;
import com.bruceeckel.tools.*;
 
public class IOStreamDemo {
  public static void main(String[] args) {
    try {
      // 1. Buffered input file
      DataInputStream in =
        new DataInputStream(
          new BufferedInputStream(
            new FileInputStream(args[0])));
      String s, s2 = new String();
      while((s = in.readLine())!= null)
        s2 += s + "n";
      in.close();
 
      // 2. Input from memory
      StringBufferInputStream in2 =
          new StringBufferInputStream(s2);
      int c;
      while((c = in2.read()) != -1)
        System.out.print((char)c);
 
      // 3. Formatted memory input
      try {
        DataInputStream in3 =
          new DataInputStream(
            new StringBufferInputStream(s2));
        while(true)
          System.out.print((char)in3.readByte());
      } catch(EOFException e) {
        System.out.println(
          "End of stream encountered");
      }
 
      // 4. Line numbering & file output
      try {
        LineNumberInputStream li =
          new LineNumberInputStream(
            new StringBufferInputStream(s2));
        DataInputStream in4 =
          new DataInputStream(li);
        PrintStream out1 =
          new PrintStream(
            new BufferedOutputStream(
              new FileOutputStream(
                "IODemo.out")));
        while((s = in4.readLine()) != null )
          out1.println(
            "Line " + li.getLineNumber() + s);
        out1.close(); // finalize() not reliable!
      } catch(EOFException e) {
        System.out.println(
          "End of stream encountered");
      }
 
      // 5. Storing & recovering data
      try {
        DataOutputStream out2 =
          new DataOutputStream(
            new BufferedOutputStream(
              new FileOutputStream("Data.txt")));
        out2.writeBytes(
          "Here's the value of pi: n");
        out2.writeDouble(3.14159);
        out2.close();
        DataInputStream in5 =
          new DataInputStream(
            new BufferedInputStream(
              new FileInputStream("Data.txt")));
        System.out.println(in5.readLine());
        System.out.println(in5.readDouble());
      } catch(EOFException e) {
        System.out.println(
          "End of stream encountered");
      }
 
      // 6. Reading/writing random access files
      RandomAccessFile rf =
        new RandomAccessFile("rtest.dat", "rw");
      for(int i = 0; i < 10; i++)
        rf.writeDouble(i*1.414);
      rf.close();
 
      rf =
        new RandomAccessFile("rtest.dat", "rw");
      rf.seek(5*8);
      rf.writeDouble(47.0001);
      rf.close();
 
      rf =
        new RandomAccessFile("rtest.dat", "r");
      for(int i = 0; i < 10; i++)
        System.out.println(
          "Value " + i + ": " +
          rf.readDouble());
      rf.close();
 
      // 7. File input shorthand
      InFile in6 = new InFile(args[0]);
      String s3 = new String();
      System.out.println(
        "First line in file: " +
        in6.readLine());
        in6.close();
 
      // 8. Formatted file output shorthand
      PrintFile out3 = new PrintFile("Data2.txt");
      out3.print("Test of PrintFile");
      out3.close();
 
      // 9. Data file output shorthand
      OutFile out4 = new OutFile("Data3.txt");
      out4.writeBytes("Test of outDataFilenr");
      out4.writeChars("Test of outDataFilenr");
      out4.close();
 
    } catch(FileNotFoundException e) {
      System.out.println(
        "File Not Found:" + args[0]);
    } catch(IOException e) {
      System.out.println("IO Exception");
    }
  }
} ///:~ 

Input
streams

Of
course, one common thing you’ll want to do is print formatted output to
the console, but that’s already been simplified in the package
com.bruceeckel.tools
created in Chapter 5.

Parts
1 through 4 demonstrate the creation and use of input streams (although part 4
also shows the simple use of an output stream as a testing tool).


1.
Buffered input file


2.
Input from memory


3.
Formatted memory input

//: TestEOF.java
// Testing for the end of file while reading
// a byte at a time.
import java.io.*;
 
public class TestEOF {
  public static void main(String[] args) {
    try {
      DataInputStream in =
        new DataInputStream(
         new BufferedInputStream(
          new FileInputStream("TestEof.java")));
      while(in.available() != 0)
        System.out.print((char)in.readByte());
    } catch (IOException e) {
      System.err.println("IOException");
    }
  }
} ///:~ 

Note
that
available( )
works differently depending on what sort of medium you’re reading from
– it’s literally “the number of bytes that can be read
without
blocking
.”
With a file this means the whole file, but with a different kind of stream this
might not be true, so use it thoughtfully.

You
could also detect the end of input in cases like these by catching an
exception. However, the use of exceptions for control flow is considered a
misuse of that feature.


4.
Line numbering and file output

Output
streams


5.
Storing and recovering data


6.
Reading and writing random access files

As
previously noted, the
RandomAccessFile
is almost totally isolated from the rest of the IO hierarchy, save for the fact
that it implements the
DataInput
and
DataOutput
interfaces. So you cannot combine it with any of the aspects of the
InputStream
and
OutputStream
subclasses. Even though it might make sense to treat a
ByteArrayInputStream
as a random access element, you can use
RandomAccessFile
to only open a file. You must assume a
RandomAccessFile
is properly buffered since you cannot add that.

The
one option you have is in the second constructor argument: you can open a
RandomAccessFile
to read (
“r”)
or read and write (
“rw”).

Shorthand
for file manipulation


7.
File input shorthand

The
creation of an object that reads a file from a buffered
DataInputStream
can be encapsulated into a class called
InFile:

//: InFile.java
// Shorthand class for opening an input file
package com.bruceeckel.tools;
import java.io.*;
 
public class InFile extends DataInputStream {
  public InFile(String filename)
    throws FileNotFoundException {
    super(
      new BufferedInputStream(
        new FileInputStream(filename)));
  }
  public InFile(File file)
    throws FileNotFoundException {
    this(file.getPath());
  }
} ///:~ 

Both
the
String
versions of the constructor and the
File
versions are included, to parallel the creation of a
FileInputStream.

Now
you can reduce your chances of repetitive stress syndrome while creating files,
as seen in the example.


8.
Formatted file output shorthand

The
same kind of approach can be taken to create a
PrintStream
that writes to a buffered file. Here’s the extension to
com.bruceeckel.tools:

//: PrintFile.java
// Shorthand class for opening an output file
// for human-readable output.
package com.bruceeckel.tools;
import java.io.*;
 
public class PrintFile extends PrintStream {
  public PrintFile(String filename)
    throws IOException {
    super(
      new BufferedOutputStream(
        new FileOutputStream(filename)));
  }
  public PrintFile(File file)
    throws IOException {
    this(file.getPath());
  }
} ///:~ 

Note
that it is not possible for a constructor to catch an exception that’s
thrown by a base-class constructor.


9.
Data file output shorthand

Finally,
the same kind of shorthand can create a buffered output file for data storage
(as opposed to human-readable storage):

//: OutFile.java
// Shorthand class for opening an output file
// for data storage.
package com.bruceeckel.tools;
import java.io.*;
 
public class OutFile extends DataOutputStream {
  public OutFile(String filename)
    throws IOException {
    super(
      new BufferedOutputStream(
        new FileOutputStream(filename)));
  }
  public OutFile(File file)
    throws IOException {
    this(file.getPath());
  }
} ///:~ 

It
is curious (and unfortunate) that the Java library designers didn’t think
to provide these conveniences as part of their standard.

Reading
from standard input

//: Echo.java
// How to read from standard input
import java.io.*;
 
public class Echo {
  public static void main(String[] args) {
    DataInputStream in =
      new DataInputStream(
        new BufferedInputStream(System.in));
    String s;
    try {
      while((s = in.readLine()).length() != 0)
        System.out.println(s);
      // An empty line terminates the program
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
} ///:~ 

Piped
streams

More by Author

Must Read