The Java I/O stream library does satisfy the basic requirements: you can perform reading and writing with the console, a file, a block of memory, or even across the Internet. With inheritance, you can create new types of input and output objects. And you can even add a simple extensibility to the kinds of objects a stream will accept by redefining the toString( ) method thats automatically called when you pass an object to a method thats expecting a String (Javas limited automatic type conversion).
There are questions left unanswered by the documentation and design of the I/O stream library. For example, it would have been nice if you could say that you want an exception thrown if you try to overwrite a file when opening it for outputsome programming systems allow you to specify that you want to open an output file, but only if it doesnt already exist. In Java, it appears that you are supposed to use a File object to determine whether a file exists, because if you open it as a FileOutputStream or FileWriter, it will always get overwritten.
The I/O stream library brings up mixed feelings; it does much of the job and its portable. But if you dont already understand the decorator pattern, the design is not intuitive, so theres extra overhead in learning and teaching it. Its also incomplete; for example, I shouldnt have to write utilities like TextFile, and theres no support for the kind of output formatting that virtually every other languages I/O package supports.
However, once you do understand the decorator pattern and begin using the library in situations that require its flexibility, you can begin to benefit from this design, at which point its cost in extra lines of code may not bother you as much.
If you do not find what youre looking for in this chapter (which has only been an introduction and is not meant to be comprehensive), you can find in-depth coverage in Java I/O, by Elliotte Rusty Harold (OReilly, 1999).