标题：OutputStream
java的OutputStream的类型
这一类别包括的类决定了我们的输入往何处去：
一个字节数组（但没有String；假定我们可用字节数组创建一个）；
一个文件；或者一个“管道”。
除此以外，FilterOutputStream为“破坏器”类提供了一个基础类，它将属性或者有用的接口同输出流连接起来。这将在以后讨论。
表10.2 OutputStream的类型
                         <th width="85">            Class　　</th>            <th width="94">            Function　　</th>            <th width="157">            Constructor Arguments　　</th>                             <th width="157">            How to use it　　</th>ByteArray-OutputStreamCreates a buffer in memory. All the data that you send to the stream is placed in this buffer.Optional initial size of the buffer.To designate the destination of your data. Connect it to a FilterOutputStream object to provide a useful interface.File-OutputStreamFor sending information to a file.A String representing the file name, or a File or FileDescriptor object.To designate the destination of your data. Connect it to a FilterOutputStream object to provide a useful interface.Piped-OutputStreamAny information you write to this automatically ends up as input for the associated PipedInput-Stream. Implements the “piping” concept.PipedInputStreamTo designate the destination of your data for multithreading. Connect it to a FilterOutputStream object to provide a useful interface.Filter-OutputStreamAbstract class which is an interface for decorators that provide useful functionality to the other OutputStream classes. See Table 
10-4.See Table 10-4.See Table 10-4.
类 功能 构建器参数／如何使用
ByteArrayOutputStream 在内存中创建一个缓冲区。我们发送给流的所有数据都会置入这个缓冲区。 可选缓冲区的初始大小／用于指出数据的目的地。若将其同FilterOutputStream对象连接到一起，可提供一个有用的接口
FileOutputStream 将信息发给一个文件 用一个String代表文件名，或选用一个File或FileDescriptor对象／用于指出数据的目的地。若将其同FilterOutputStream对象连接到一起，可提供一个有用的接口
PipedOutputStream 我们写给它的任何信息都会自动成为相关的PipedInputStream的输出。实现了“管道化”的概念 PipedInputStream／为多线程处理指出自己数据的目的地／将其同FilterOutputStream对象连接到一起，便可提供一个有用的接口
FilterOutputStream 对作为破坏器接口使用的类进行抽象处理；那个破坏器为其他OutputStream类提供了有用的功能。参见表10.4
OutputStream的使用方法
根据写数据的方式不同，OutputStream主要分成两类；一类是写给人看的，一类是供DataInputStream用的。虽然RandomAccessFile的数据格式同DataInputStream和DataOutputStream的相同，但它不属于OutputStream的。存储和恢复数据PrintWriter会对数据进行格式化，这样人就能读懂了。但是如果数据输出之后，还要恢复出来供其它流用，那你就必须用DataOutputStream来写数据，再用DataInputStream来读数据了。当然，它们可以是任何流，不过我们这里用的是一个经缓冲的文件。DataOutputStream和DataInputStream是面向byte的，因此这些流必须都是InputStream和OutputStream。
如果数据是用DataOutputStream写的，那么不管在哪个平台上，DataInputStream都能准确地把它还原出来。这一点真是太有用了，因为没人知道谁在为平台专属的数据操心。如果你在两个平台上都用Java，那这个问题就根本不存在了 。
用DataOutputStream写String的时候，要想确保将来能用DataInputStream恢复出来，唯一的办法就是使用UTF-8编码，也就是像例程第5部分那样，用writeUTF( )和readUTF( )。UTF-8是Unicode的一种变形。Unicode用两个字节来表示一个字符。但是，如果你处理的全部，或主要是ASCII字符(只有7位)，那么无论从存储空间还是从带宽上看，就都显得太浪费了，所以UTF-8 用一个字节表示ASCII字符，用两或三个字节表示非ASCII的字符。此外，字符串的长度信息存在(字符串)的头两个字节里。writeUTF( )和readUTF( )用的是Java自己的UTF-8版本(JDK文档里有关于这个字符集的完整讲解，就在这两个方法的文档里)，所以如果你要用一个Java程序读取writeUTF( )写的字符串的话，就必须进行一些特殊处理了。
有了writeUTF( )和readUTF( )，你就能放心地把String和其它数据混在一起交给DataOutputStream了，因为你知道String是以Unicode的形式存储的，而且可以很方便地用DataOutputStream恢复出来。
writeDouble( )会往流里写double，而它"影子"readDouble( )则负责把它恢复出来(其它数据也有类似的读写方法)。但是要想让读取方法能正常工作，你就必须知道流的各个位置上都放了些什么数据。因为你完全可以把double读成byte，char，或其它什么东西。所以要么以固定的格式写文件，要么在文件里提供额外的解释信息，然后一边读数据一边找数据。先提一下，对于复杂数据的存储和恢复，对象的序列化可能会比较简单。读写随机文件正如我们前面所讲的，如果不算它实现了DataInput和DataOutput接口，RandomAccessFile几乎是完全独立于其它I/O类库之外的，所以它不能与InputStream和OutputStream合起来用。虽然把ByteArrayInputStream当作"随机存取的元素(random-access element)"是一件很合情合理的事，但你只能用RandomAccessFile来打开文件。而且，你只能假定RandomAccessFile已经做过缓冲了，因为即便没做你也无能为力。
构造函数的第二个参数的意思是：是以只读("r") 还是读写("rw")方式打开RandomAccessFile。
RandomAccessFile的用法就像是DataInputStream和DataOutputStream的结合(因为它们的接口是等效的)。此外，你还能用seek( )在文件里上下移动，并进行修改。
随着JDK 1.4的new I/O的问世，你该考虑一下是不是用"内存映射文件(memory-mapped file)"来代替RandomAccessFile了。