流与文件

来源:互联网 发布:php简单工作流 编辑:程序博客网 时间:2024/05/16 23:46

12. 流与文件 - core java 7

12.1 流

流是字节序列从源到目的的传送. 其源和目的可以是文件也可以是网络连接或内存块.

在Java中有很多流类.

InputStream
 |
 |-AudioInputStream
 |-ByteArrayInputStream
 |-FileInputStream  //用来得到文件的输入流. 但读2进制数据应该用RandomAccessFile
 |-PipedInputStream //管道流
 |-SequenceInputStream
 |-StringBufferInputStream
 |-ObjectInputStream ----------->    <<interface>> ObjectInput
 |-FilterInputStream   //流过滤器类. 构造器接收一个InputStream对象. 应该是装饰模式.
    |-BufferedInputStream  //使一个流称为带缓冲能力的流(缺省是不缓冲的).
    |-CheckedInputStream  //
    |-CipherInputStream
    |-DigestInputStream
    |-LineNumberInputStream
    |-ProgressMonitorInputStream
    |-PushbackInputStream  //它可以让流支持预读一个字节的功能.
    |-DataInputStream   //实现了DataInput接口. 所以有读取2进制数据的方法.
    |-InflaterInputStream
       |-GZIPInputStream
       |-ZipInputStream
          |-JarInputStream

OutputStream
 |-ByteArrayOutputStream
 |-FileOutputStream  // //用来得到文件的输出流. 但写2进制数据应该用RandomAccessFile
 |-PipedOutputStream  //管道流
 |-ObjectOutPutStream ------------>  <<interface>>ObjectOutput
 |-FilterOutputStream //流过滤器类
    |-BufferedOutputStream  //缓冲
    |-CheckedOutputStream
    |-CipherOutputStream
    |-DigestOutputStream
    |-PrintStream
    |-DataOutputStream  //实现了DataOutput接口. 所以有写入2进制数据的方法.
    |-DeflaterOutputStream
       |-GZIPOutputStream
       |-ZipOutputStream
          |-JarOutputStream


Reader
 |-BufferedReader
 |  |-LineNumberReader
 |
 |-CharArrayReader
 |-FilterReader
 |  |-PushbackReader
 |
 |-InputStreamReader
 |  |-FileReader
 |
 |-PipedReader
 |-StringReader


Writer
 |-BufferedWriter
 |-CharArrayWriter
 |-FilterWriter
 |-PipedWriter
 |-PrintWriter  //用来输出文本流. 用它提供的print() println() 会很方便.
 |-StringWriter
 |-OutputStreamWriter
    |-FileWriter


流分为输入流和输出流.
抽象类InputStream和Reader表示输入流. OutputStream和Writer表示输出流.
其中Reader和Writer输入/输出的是Unicode字符(16位).
4种流都实现了Closeable接口.所以有方法void close()throws IOException.
输出流OutputStream和Writer还实现了Flushable接口. 所以有方法void flush().
Reader类还实现了Readable接口. 所以有方法int read(CharBuffer cb).
Writer类还实现了Appendable接口.所以它有两个方法用来向流追加字符或字符序列.


InputStream类有方法:
    abstract int read()throws IOException //抽象方法.读一个字节并将其返回.若读到末尾则返回-1.
             //注意它可能阻塞当前线程.
    int read(byte[] b) throws IOException //相当于调用下边的 read(b, 0, b.length)
    int read(byte[] b, int off, int len) throws IOException
          //尝试读入len字节. 存入b[off]开始的缓冲区中. 它读取的时候会调用int read()来依次读入每个
          //字节. 若读第一个字节时导致read()抛出IOException则本函数也抛出IOException, 但在后续
          //的调用中read()抛出的IOException会在本函数内被捕获而不会抛出来(此时函数会返回已经正确
          //读出的字节数).
    long skip(long n) throws IOException //跳过n字节. 返回实际跳过的字节数. 若n为负则不跳过.
    int available() throws IOException   //返回流中当前可以不受阻塞地读取(或跳过)的字节数。
    void close() throws IOException  //关闭并释放与该流关联的所有系统资源


OutputStream类的方法有:
    abstract void write(int b) throws IOException//向流写入的是参数b的低8位.高24位被忽略.
    void write(byte[] b) throws IOException //相当于write(b, 0, b.length)
    void write(byte[] b, int off, int len) throws IOException
            //向流中写入b[off]开始的len个字节.
    void flush() throws IOException  //刷新此输出流并强制写出所有缓冲的字节
    void close() throws IOException  //关闭此输出流并释放与此流有关的所有系统资源


Reader类的方法有:
    int read() throws IOException  //读取单个字符
    int read(CharBuffer target) throws IOException
            //试图将字符读入指定的字符缓冲区.返回读入的字符数.
    int read(char[] cbuf) throws IOException //将字符读入数组. 返回读入的字符数.
    abstract int read(char[] cbuf, int off, int len) throws IOException
           //将字符读入cbuf[off]开始的地方
    long skip(long n) throws IOException  //跳过n个字符
    boolean ready() throws IOException //若下一个read()不阻塞则返回True
    boolean markSupported()  //判断此流是否支持 mark() 操作
    void mark(int readAheadLimit) throws IOException  //标记流中的当前位置.和reset()合用.
    void reset() throws IOException  //重置该流到mark()处.若目前尚未mark或已实效则抛出异常.
    void close() throws IOException  //关闭该流


Writer类的方法:
    void write(int c) throws IOException  //写入单个char(即c的低16位).
    void write(char[] cbuf) throws IOException  //写入字符数组
    void write(char[] cbuf, int off, int len) throws IOException //写入字符数组的一部分
    void write(String str) throws IOException  //写入字符串
    void write(String str, int off, int len) throws IOException //写入字符串的一部分
    Writer append(CharSequence csq) throws IOException //将字符序列追加到此 writer
    Writer append(CharSequence csq, int start, int end) throws IOException
                //将指定字符序列的子序列追加到此 writer
    Writer append(char c) throws IOException  //将指定字符追加到此 writer
    void flush() throws IOException  //刷新此流
    void close() throws IOException  //关闭此流

上边介绍的4种流类(InputStream,OutputStream,Reader,Writer)都是抽象类.
下边看看具体的实际使用的流类.

PrintWriter类
它派生于Writer类. 并且它也有和PrintStream中一样的print()/println()方法.
所以它用来方便的输出文本流.
构造方法:
    PrintWriter(File file) 
    PrintWriter(OutputStream out) 
    PrintWriter(OutputStream out, boolean autoFlush)//第2个参数为是否自动刷新.缺省为否.
    PrintWriter(String fileName)
    PrintWriter(Writer out)
    PrintWriter(Writer out, boolean autoFlush)
其它方法:
    它继承自Writer.所以有Writer的write() append() 等方法.
    并且还有以下的各种print方法:
    void print(boolean b) //打印 boolean 值。
    void print(char c)
    void print(char[] s)
    void print(double d)
    void print(float f)
    void print(int i)
    void print(long l)
    void print(Object obj)
    void print(String s)
    PrintWriter printf(Locale l, String format, Object... args)
            //使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。
    PrintWriter printf(String format, Object... args)
            //使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。
    void println()  //通过写入行分隔符字符串终止当前行。
    void println(boolean x)
    void println(char x)
    void println(char[] x)
    void println(double x)
    void println(float x)
    void println(int x)
    void println(long x)
    void println(Object x)
    void println(String x)


流经常和磁盘文件关联. 要得到一个文件的输入流或输出流用:
FileInputStream 和 FileOutputStream
这两个类用来得到一个磁盘文件的输入流或输出流.
这两个流从文件中读写文本内容很方便.但不能读写2进制数据.
它们继承自InputStream和OutputStream. 所以分别有read() / write()方法用来读写文本.
构造方法(若文件无法打开抛出FileNotFoundException):
    FileInputStream(File file)
    FileInputStream(FileDescriptor fdObj)
    FileInputStream(String name)
    FileOutputStream(File file)
    FileOutputStream(File file, boolean append)  //若append为True则写入时写入文件末尾.
    FileOutputStream(FileDescriptor fdObj)
    FileOutputStream(String name)
    FileOutputStream(String name, boolean append) 
这两个类得到的流是字节流.要得到字符(16位)流可以用对应的FileReader类和FileWriter类.

不过FileInputStream / FileOutputStream 以及 FileReader / FileWriter都不能读写2进制的数据.
所以就需要下边的RandomAccessFile(随机存取文件流)类:


2进制IO

先看看2进制流类的接口:

<<interface>>DataInput -|
                        |- RandomAccessFile
<<interface>>DataOutput-|

其中接口DataInput是2进制输入流的接口. 方法有:
    boolean readBoolean()  //读取一个输入字节,如果该字节不是零,则返回 true
    byte readByte()  //读取并返回一个输入字节。
    char readChar() //读取一个输入的 char 并返回该 char 值。
    double readDouble()  //读取八个输入字节并返回一个 double 值。
    float readFloat()  //读取四个输入字节并返回一个 float 值。
    void readFully(byte[] b)  //从输入流中读取一些字节,并将它们存储到缓冲区数组 b 中。
    void readFully(byte[] b, int off, int len) //从输入流中读取 len 个字节。
    int readInt() //读取四个输入字节并返回一个 int 值。
    String readLine() //从输入流中读取下一文本行。
    long readLong() //读取八个输入字节并返回一个 long 值。
    short readShort() //读取两个输入字节并返回一个 short 值。
    int readUnsignedByte() //读取一个输入字节,将它左侧补零 (zero-extend) 转变为 int 类型,
                           //并返回结果,所以结果的范围是 0 到 255。
    int readUnsignedShort()  //读取两个输入字节,并返回 0 到 65535 范围内的一个 int 值。
    String readUTF()   //读入一个已使用 UTF-8修改版格式编码的字符串。该格式根据字符的大小用
                        //1到3个字节存储字符
    int skipBytes(int n)  //试图在输入流中跳过数据的 n 个字节,并丢弃跳过的字节。


接口DataOutput是2进制输出流的接口. 方法有:
    void write(byte[] b) //将数组 b 中的所有字节写入输出流。
    void write(byte[] b, int off, int len) //将数组 b 中的 len 个字节按顺序写入输出流。
    void write(int b)  //将参数 b 的八个低位写入输出流。
    void writeBoolean(boolean v)  //将一个 boolean 值写入输出流。
    void writeByte(int v) //将参数 v 的八个低位写入输出流。
    void writeBytes(String s)  //将一个字符串写入输出流。
    void writeChar(int v)  //将一个 char 值写入输出流,该值由两个字节组成。
    void writeChars(String s) //将字符串 s 中的所有字符按顺序写入输出流,每个字符用两字节表示
    void writeDouble(double v) //将一个 double 值写入输出流,该值由八个字节组成。
    void writeFloat(float v) //将一个 float 值写入输出流,该值由四个字节组成。
    void writeInt(int v)  //将一个 int 值写入输出流,该值由四个字节组成。
    void writeLong(long v) //将一个 long 值写入输出流,该值由八个字节组成。
    void writeShort(int v) //将两个字节写入输出流,用它们表示参数值。
    void writeUTF(String str) //将表示长度信息的两个字节写入输出流,
                          //后跟字符串 s 中每个字符的 UTF-8 修改版表示形式。
                          //该格式根据每个字符的值来用1到3个字节表示


随机存取文件流 RandomAccessFile
这个类实现了 DataInput 和 DataOutput 两个接口.  它可以读写文本内容或2进制内容
它的构造器
    RandomAccessFile(String name, String mode)
    public RandomAccessFile(File file, String mode)
的第2个参数可以是"r"或"rw" . 分别表示"只读"或"读写".
随机读取文件类有一个文件指针. 可以检查/设置此文件指针来随机读写:
    long getFilePointer() //返回此文件中文件指针的当前偏移量
    void seek(long pos)  //设置到此文件指针的偏移量 
检查/设置文件长度用:
    long length() //返回此文件的长度
    void setLength(long newLength) //设置此文件的长度
读写数据使用DataInput和DataOutput接口中声明的方法.以及下边几个read方法:
    int read() //读取一个数据字节。
    int read(byte[] b) //将最多 b.length 个数据字节从此文件读入字节数组。
    int read(byte[] b, int off, int len)


上边的RandomAccessFile类的构造方法的参数是File类的对象.
这个File类是什么? 就是一个抽象的路径名. 下边我们看这个类


File类
这个类表示文件和目录. 它只是一个抽象的路径名. 并不能用它来读写数据.
构造方法:
    File(File parent, String child) //用parent和child字符串创建一个新的File实例。
    File(String pathname)  //将给定字符串转换成抽象路径名来创建一个新 File 实例。
    File(String parent, String child) //用parent字符串和child字符串创建一个新File实例。
    File(URI uri) //将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。
其它方法:
    static File[] listRoots() //列出可用的文件系统根目录。
    static File createTempFile(String prefix, String suffix)
             //在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
    static File createTempFile(String prefix, String suffix, File directory)
              //在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
    boolean canRead() //是否可以读取此抽象路径名表示的文件。
    boolean canWrite() //是否可以修改此抽象路径名表示的文件。
    int compareTo(File pathname) //按字母顺序比较两个抽象路径名。
    boolean createNewFile()  //当且仅当不存在具有此抽象路径名指定的名称的文件时
                     //原子地创建由此抽象路径名指定的一个新的空文件。 
    boolean delete() //删除此抽象路径名表示的文件或目录。
    void deleteOnExit() //在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
    boolean equals(Object obj) 
    boolean exists() //测试此抽象路径名表示的文件或目录是否存在。
    File getAbsoluteFile() //返回抽象路径名的绝对路径名形式。
    String getAbsolutePath() //返回抽象路径名的绝对路径名字符串。
    File getCanonicalFile() //返回此抽象路径名的规范形式。
    String getCanonicalPath() //返回抽象路径名的规范路径名字符串。
    String getName() //返回由此抽象路径名表示的文件或目录的名称。
    String getParent() //返回此抽象路径名的父路径名的路径名字符串
                    //如果此路径名没有指定父目录,则返回 null。
    File getParentFile()  //返回此抽象路径名的父路径名的抽象路径名
                          //如果此路径名没有指定父目录,则返回 null。
    String getPath()  //将此抽象路径名转换为一个路径名字符串。
    int hashCode() //计算此抽象路径名的哈希码。
    boolean isAbsolute() //是否为绝对路径名
    boolean isDirectory() //是否是一个目录
    boolean isFile() //是否是一个标准文件
    boolean isHidden() //是否是一个隐藏文件
    long lastModified() //最后一次被修改的时间
    long length() //表示的文件的长度。
    String[] list() //目录中的文件和目录的名称所组成字符串数组。
    String[] list(FilenameFilter filter) //目录中的文件和目录的名称所组成的字符串数组
                //这一目录是通过满足指定过滤器的抽象路径名来表示的
    File[] listFiles()   //和上边的方法类似. 返回目录下所有子目录和文件的File对象
    File[] listFiles(FileFilter filter) 
    File[] listFiles(FilenameFilter filter)
    boolean mkdir() //创建此抽象路径名指定的目录。
    boolean mkdirs() //创建此抽象路径名指定的目录,若它的父目录不存在则一起创建之
    boolean renameTo(File dest) //重新命名此抽象路径名表示的文件。
    boolean setLastModified(long time) //设置文件或目录的最后一次修改时间。
    boolean setReadOnly() //使该文件或目录只读
    String toString() //返回此抽象路径名的路径名字符串。
    URI toURI() //构造一个表示此抽象路径名的 file: URI。
    URL toURL() //将此抽象路径名转换成一个 file: URL。

///////////////////////    未完 待续 ////////////////////////


管道流
PipedOutputStream
PipedInputStream
它们可以在不同的线程间传递数据.  跳过~~~~~ 以后看~~~


27.7 字节数组流 -Java2详解
ByteArrayInputStream 和 ByteArrayOutputStream
流并不总是和文件关联呀. 也可以和一个内存缓冲区关联.
而这两个类就是提供这样的功能. 它类似于c++STL中的 istringstream 和 ostringstream .
构造方法:
    ByteArrayInputStream(byte[] buf) //使用 buf 数组作为其缓冲区。
    ByteArrayInputStream(byte[] buf, int offset, int length)
        //只能从缓冲流读length字节. 这两个构造方法得到的流的缓冲区就是buf数组而不是buf的拷贝.
    ByteArrayOutputStream() //创建新的字节数组输出流。
    ByteArrayOutputStream(int size) //参数size指定缓冲区的容量(字节数).
其他方法:
    ByteArrayInputStream只有其父类InputStream中声明的方法.
    而ByteArrayOutputStream类的方法有:
        void reset() //清空输出流中目前已累积的所有输出
        int size() //返回缓冲区的当前已经写入的字节数。
        byte[] toByteArray() //返回输出的流的字节数组表示. 该字节数组是新分配的.
        String toString() //将缓冲区的内容转换为字符串
                          //根据平台的默认字符编码将字节转换成字符。
        String toString(String enc)  //参数为转换为字符串时使用的字符编码
        void write(byte[] b, int off, int len)
                 //将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流。
        void write(int b) //将指定的字节(b的低8位)写入此字节数组输出流
        void writeTo(OutputStream out)  //将流的内容写入到参数指定的输出流中


27.8 字符数组流 -Java2详解
CharArrayReader 和 CharArrayWriter
这两个类是上边 ByteArrayInputStream 和 ByteArrayOutputStream 的字符(16位)版本.
功能和方法很类似.  构造方法为:
    CharArrayReader(char[] buf)
    CharArrayReader(char[] buf, int offset, int length)
    CharArrayWriter()
    CharArrayWriter(int size)


27.10 StringBufferInputStream
这个类和ByteArrayInputStream的功能类似. 区别是ByteArrayInputStream的构造方法的参数是
Byte[] 而 StringBufferInputStream 构造方法的参数是 String :
构造方法:
    StringBufferInputStream(String str)


27.9 字节流到字符流的转换 -Java2详解

要让字节流(8位)转换为字符流(16位). 使用下边两个类:
InputStreamReader 和 OutputStreamWriter
它们是Reader和Writer的子类. 但它们的参数却是InputStream和OutputStream.
这样就可以用一个字节流来构造一个字符流. 并使用字符流Reader/Writer的方法读写.
它们的构造方法如:
    InputStreamReader(InputStream in)
    OutputStreamWriter(OutputStream out)
它们还有其它构造方法用以指定字符流到字节流转换使用的编码.


27.4.7 流过滤器类 FilterInputStream  -Java2详解
下边是一些流的过滤器类.它们派生自FilterInputStream.
它们的构造方法都是接收一个InputStream对象. 所以可以有很多层这样的过滤器. 应该是装饰模式.


27.5 缓冲区例的流 -Java2详解
BufferedInputStream / BufferedOutputStream
是流过滤器类. 派生于FilterInputStream / FilterOutputStream .
它们使输入/输出流具有缓冲能力. 提高性能.
BufferedInputStream在调用read()方法时会将尽可能多的数据读入缓冲区.
BufferedOutputStream则是只有在缓冲区写满或调用flush方法时才调用write()方法.
构造方法:
    BufferedInputStream(InputStream in)
    BufferedInputStream(InputStream in, int bufferSize) //指定缓冲大小
    BufferedOutputStream(OutputStream in)
    BufferedOutputStream(OutputStream in, int bufferSize)


27.6 数据流 -Java2详解
DataInputStream 和 DataOutputStream
是流过滤器类. 派生于FilterInputStream / FilterOutputStream .
并且它们还实现了 DataInput接口 / DataOutput接口.
所以当读写2进制数据的时候. 需要用这种流过滤器. 它拥有readInt()/writeDouble()这样的方法.
它们的构造器为:
    DataInputStream(InputStream in)
    DataOutputStream(OutputStream out)


27.11 对象流
为了直接读写一个类对象. 提供了 ObjectInput 接口和 ObjectOutput 接口.
ObjectInput接口扩展了DataInput接口.并添加了唯一的方法:
    Object readObject() throws ClassNotFoundException, IOException
ObjectOutput接口扩展了DataOutput接口. 并添加了唯一的方法:
    void writeObject(Object obj) throws IOException