彻底解决java的io流问题.

Javaio流,是一个很容易混淆的概念,里面涉及了很深层次的类继承,并且应用了著名的装饰模式,首先,我们来看下io流的具体类提及其应用和概念;

 

首先,流是什么?流是什么?流来自java.io包,

形象的比喻——水流 ,文件======程序 ,文件和程序之间连接一个管道,水流就在之间形成了,自然也就出现了方向:可以流进,也可以流出.便于理解,这么定义流: 流就是一个管道里面有流水,这个管道连接了文件和程序。

 

根据流的方向划分,我们分为流进流和流出流:


  
  
   
    
  
  
流进流:
public abstract class InputStream
extends Object
implements Closeable

此抽象类是表示字节输入流的所有类的超类。

需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。

这个类是所有流入流的超类,他提供了从程序从数据源读取数据的方式:

read()

          从输入流中读取数据的下一个字节。

 int read(byte[] b)

          从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

 int read(byte[] b, int off, int len)

          将输入流中最多 len 个数据字节读入 byte 数组。

其中辅助这个读取方法的另外两个方法是:

 

 int available()

          返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

 

long skip(long n)

          跳过和丢弃此输入流中数据的 n 个字节。

相对而言:流出流正好相反:

 

 

public abstract class OutputStreamextends Objectimplements Closeable, Flushable此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

 

需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。

 

void write(byte[] b)

          b.length 个字节从指定的 byte 数组写入此输出流。

 void write(byte[] b, int off, int len)

          将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

abstract  void write(int b)

          将指定的字节写入此输出流

正好,这个两个接口提供了java 的基本输入输出功能;

 

字节流在传输的时候,更多的是方便我们传输二进制的文件,如下:

package org.corey.servlet;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

 

public class IODemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       File srcFile = new File("c:/a.jpg");

       File tgtFile = new File("d:/a.jpg");

       try {

           FileInputStream fin = new FileInputStream(srcFile);

           byte[] bts = new byte[fin.available()];

           fin.read(bts, 0, fin.available() - 1);

           fin.close();

          

           FileOutputStream fos = new FileOutputStream(tgtFile);

           fos.write(bts);

           fos.close();

          

       } catch (Exception e) {

           e.printStackTrace();

       }

 

    }

 

}

 

在此接口的功能基础上,根据数据来源的不同以及和数据流向的不同,扩展了几个类:分别是:

InputStream:

AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream

 

OutputStream:

ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream

 

诸如:

package org.corey.servlet;

 

import java.io.ByteArrayInputStream;

import java.io.File;

 

public class IODemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       try {

           byte[] buffer=new byte[]{1,2,3,4,5,6};

           ByteArrayInputStream bts=new ByteArrayInputStream(buffer);

           int byteValue;

           while((byteValue=bts.read())!=-1){

              System.out.println(byteValue);

           }

       } catch (Exception e) {

           System.out.println("create the fin is error");

           e.printStackTrace();

       }

 

    }

 

}

package org.corey.servlet;

 

import java.io.ByteArrayOutputStream;

 

public class IODemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       try {

           byte[] buffer = new byte[] { 1, 2, 3, 4, 5, 6 };

           byte[] targetBuffer;

           ByteArrayOutputStream bos = new ByteArrayOutputStream(10);

           bos.write(buffer);

           targetBuffer=bos.toByteArray();

           int arrayIndex=0;

           while(arrayIndex<buffer.length){

           System.out.println(targetBuffer[arrayIndex]);

           arrayIndex++;

           }

          

       } catch (Exception e) {

           System.out.println("create the fin is error");

           e.printStackTrace();

       }

 

    }

 

}

 

 

基于字符形式的io

以上接口操作的方法,都是基于字节的,我们知道,一个字符串,经过解码以后,可以解码成为二进制位,二进制位更抽象的表示成为字节数组,而javaunicode编码的,所以在java里面还有两个基于字符的流入流和流出流;方便我们操纵一个文本数据的io流进流出,

 

同样,操纵字符流的流出流和流入流也有两个对应的接口,并且提供了基本的io方法

 

字符流入流:

public abstract class Readerextends Objectimplements Readable, Closeable用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

 

          判断此流是否支持 mark() 操作。

 int read()

          读取单个字符。

 int read(char[] cbuf)

          将字符读入数组。

abstract  int read(char[] cbuf, int off, int len)

          将字符读入数组的某一部分。

 int read(CharBuffer target)

          试图将字符读入指定的字符缓冲区。

 

辅助方法有:

 

 long skip(long n)

          跳过字符。

 

字符流出流:

 

public abstract class Writerextends Objectimplements Appendable, Closeable, Flushable写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)flush() close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

 

基本的输出方法有:

void write(char[] cbuf)

          写入字符数组。

abstract  void write(char[] cbuf, int off, int len)

          写入字符数组的某一部分。

 void write(int c)

          写入单个字符。

 void write(String str)

          写入字符串。

 void write(String str, int off, int len)

          写入字符串的某一部分。

 

 

 

package org.corey.servlet;

 

import java.io.File;

import java.io.FileReader;

import java.io.FileWriter;

 

public class IODemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       File srcFile = new File("c:/a.txt");

       File tgtFile = new File("d:/a.jpg");

       try {

           FileReader fReader = new FileReader(srcFile);

           char[] cbuf=new char[256];

           int endIndex=fReader.read(cbuf);

           String fStr=new String(cbuf,0,endIndex);

           System.out.println(fStr);

       } catch (Exception e) {

           System.out.println("create the fin is error");

           e.printStackTrace();

       }

 

    }

 

}

文本文件完整的输出

 

有人会问,如果,我取得的io流是基于字节的,那么我可不可以把这些字节组装起来,变成基于字符的呢,应该可以把,我大不了把几个字节组装起来(即利用编码方式)

确实,在字节流的io操作于字符流的io操作之间是有桥梁的,那就是inputStreamReaderOutputStreamWriter

 

 

 

 

下面我们就来看看经典的装饰器模式的应用:

利用层次化对象动态和透明地添加单个对象的能力的做法叫作装饰器Decorator)方案——“方案属于本书第16章的主题(注释)。装饰器方案规定封装于初始化对象中的所有对象都拥有相同的接口,以便利用装饰器的透明性质——我们将相同的消息发给一个对象,无论它是否已被装饰。这正是在Java IO库里存在过滤器Filter)类的原因:抽象的过滤器类是所有装饰器的基础类(装饰器必须拥有与它装饰的那个对象相同的接口,但装饰器亦可对接口作出扩展,这种情况见诸于几个特殊的过滤器类中)。
子类处理要求大量子类对每种可能的组合提供支持时,便经常会用到装饰器——由于组合形式太多,造成子类处理变得不切实际。Java IO库要求许多不同的特性组合方案,这正是装饰器方案显得特别有用的原因。但是,装饰器方案也有自己的一个缺点。在我们写一个程序的时候,装饰器为我们提供了大得多的灵活性(因为可以方便地混合与匹配属性),但它们也使自己的代码变得更加复杂。原因在于Java IO库操作不便,我们必须创建许多类——“核心”IO类型加上所有装饰器——才能得到自己希望的单个IO对象。
FilterInputStream
FilterOutputStream(这两个名字不十分直观)提供了相应的装饰器接口,用于控制一个特定的输入流(InputStream)或者输出流(OutputStream)。它们分别是从InputStreamOutputStream衍生出来的。此外,它们都属于抽象类,在理论上为我们与一个流的不同通信手段都提供了一个通用的接口。事实上,FilterInputStreamFilterOutputStream只是简单地模仿了自己的基础类,它们是一个装饰器的基本要求。

 

 

 

简单的一句话就是,因为一个程序语言的io设计是很复杂的,因为他要处理的情况很多,就如java一样,我们就感觉类很多,我们很难记住,哪么java采用的方法是装饰模式,装饰模式很经典(可查询资料),意思就是可以动态的为固有类增加心的功能,java io系统就采用了这种方式,给我们本来很普通的io流增加了缓存,数据类型的输入输出等等,所有的增加心功能的类都继承于

public class FilterOutputStream
extends OutputStream

此类是过滤输出流的所有类的超类。这些流位于已存在的输出流(基础 输出流)之上,它们将已存在的输出流作为其基本数据接收器,但可能直接传输数据或提供一些额外的功能。

FilterOutputStream 类本身只是简单地重写那些将所有请求传递给所包含输出流的 OutputStream 的所有方法。FilterOutputStream 的子类可进一步地重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

 

很简单的图形比喻:

、、

正常流

 

Filter流给这个管道增加的新功能

 

 

 

 

 

 

代码如下:

package org.corey.servlet;

 

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileOutputStream;

 

public class IODemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       try {

           File targetFile = new File("c:/b.txt");

           FileOutputStream fos = new FileOutputStream(targetFile);

           DataOutputStream dos = new DataOutputStream(fos);

           dos.writeFloat( 2.3f );

           dos.writeInt(5);

           dos.close();

           fos.close();

          

           FileInputStream fis = new FileInputStream(targetFile);

           DataInputStream dis = new DataInputStream(fis);

           float floatValue=dis.readFloat();

           int intValue=dis.readInt();

           System.out.println(floatValue);

           System.out.println(intValue);

           dis.close();

           fis.close();

       } catch (Exception e) {

           System.out.println("create the fin is error");

           e.printStackTrace();

       }

 

    }

 

}

另外还有

缓冲区io功能类:

public class BufferedOutputStream
extends FilterOutputStream

该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

 

格式化io功能类:

public class PrintStream

extends FilterOutputStream

implements Appendable, Closeable

PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 ('/n')

PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。

 

不过这里要注意,对应的,不要轻易认为FilterRader也有一个子类叫做BufferedReader;

Bufferedreader是直接继承与Reader的;同样BufferedWriter也是直接继承Writer的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值