IO(Input Output)流总结(一)

来源:互联网 发布:linux进入命令行 编辑:程序博客网 时间:2024/05/16 07:34


 

IO(Input Output)流总结(一)

IO流是处理数据之间数据传输的。

Java对数据的操作是通过流的方式。

Java中用于操作IO流的对象都放在java.io包中。

流的分类:按照操作数据分为:字符流和字节流。

          按照流向分为:输入流和输出流。

 

                

                  输入流:                输出流:

  字符流:

Reader                    Writer

  |--BufferedReader           |-- BufferedWriter

  |--inputStreamReader        |--OutputStreamWriter

      |--FileReader               |--FileWriter

 

  字节流:

InputStream                 OutputStream

   |--FileInputStream           |--FileOutputStream

 

InputStream                 OutputStream

  |--FilterInputStream           |--FilterOutputStream

     |--BufferedInputStream        |-- BufferedOutputStream

 

在计算机中存储的都是1和0的序列。也就是二进制的有序序列,不论是文本、音乐或者是视频。

那么为什么要在流中定义字节流和字符流呢?

这个与我们的字符编码方式有关。我们都知道世界上有很多种的语言,比如:ASCII、GB2312、GBK、UTF-8和Unicode等。

如果一个文本文件使用GB2312编码的方式存储的,如果我们用Unicode的编码方式来读取,那么就会出现乱码。所以字符流是一种特殊的流,在java中就定义了专门处理字符的流对象。

 

当我们拿到一个API文档我们应该如何使用呢?

1,确定要使用的功能。

2,查阅API看有没有相关的功能类。

3,如果没有,就分析需要如何自定义一个出来,并且要使用到那些相关功能的类,这些类在API中有没有定义。

4,不论有或者没有需要自定义一个,我们都要先查阅相关功能类的根类,那么查阅一个API的时候我们要注意一些什么呢?

5,找到相关功能根类,先看一下它是一个类,还是接口,还是抽象类,如果是接口或者是抽象类我们就不能直接使用这个类,而要使用这个类的子类。

6,但是,我们不用急于先看它有哪些子类,我们先看一下它到底暴露了什么字段、构造函数和方法。

7,在查看暴露的信息时,我们要注意几点:

a. 如果是static修饰的,说明是静态的,我们不用new对象也可以直接使用。

b. 我们要确定自己要使用的方法将会返回的数据的类型,是void呢、String呢、int呢、还是其他的。查找的时候就重点找返回这些类型的方法。(注意:如果我们使用的类是一个使用单例设计模式设计的,那么他就没有构造函数,我们就一般可以通过静态的getIstance()方法获取相应的对象,这时我们就要找返回值是对象类型的方法。)

8,如果在根类中找到了需要的方法,但是根类又不能创建对象,那么我们就看看,继承这个根类的子类有哪些,一般子类都继承了父类的方法,所以子类可以直接调用父类的方法,并且子类又定义了一些自身特别的方法。

9,找到需要的类创建对象,或者找到相关功能的对象自定义一个需要的类。

 

下面我们按照以上的方法来阐述IO流的学习:

字节流:

字节流的根类有:读取流(Reader)、写入流(Writer)

根类都是abstract(抽象)的,我们不能直接创建对象,但是我们可以看一看父类都定义了什么方法。

Reader:

int read() 

          读取单个字符。 

int read(char[] cbuf) 

          将字符读入数组。 

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

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

int  read(CharBuffer target) 

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

abstract  void close() 

          关闭该流并释放与之关联的所有资源。 

 

FileReader:Reader的子类,可以创建对象,专门用来操作字符数据流的。

 

Writer:

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) 

          写入字符串的某一部分。 

abstract  void close() 

          关闭此流,但要先刷新它。 

abstract  void flush() 

          刷新该流的缓冲。 

 

写入流(Writer)在每次调用write()方法的时候都要flush()(刷新)一次,当然Writer也不能创建对象,我们可以使用他的子类FileWriter,FileWriter是专门处理字符写入流的类。

 

FileReader 和 FileWriter 为我们提供了操作字符数据流的一般方法,其中比较高效的就是自定义一个数组,用这个数组作为临时存储区,每次读取一块(装满数组)数据,然后再将这一块数据写入相应的目的地。这样就提高了效率,如果每次读取一个字符然后写入一个字符,就很低效,是不可取的。

自定一个数组为我们提高了效率,但是每次使用都要写很多代码,所以开发者就将这个数组封装为了一个特殊的对象。那就是缓冲区!BufferedReader(字符读取缓冲区)和BufferedWriter(字符写入缓冲区)。他是用的是装饰设计模式,是再不改变原来已定义类的基础上增强类的功能。

补充:BufferedReader的子类LineNumberReader,增加了int getLineNumber() :获得当前行号的功能,我们可以在使用缓冲区的同时读取行号。

 

装饰设计模式:

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。

 

字符流学习完了,那么如果要学习字节流就会简单很多,我们通过查阅API知道:很多方法都似曾相识。所以,总结一下就是下面几点:

A. 字节流分为:InputStream(读取流)和OutputStream(写入流)

B. 字节流和字符流的功能基本相同,只不过传入的参数由字符流中的字节char,变成了字节中的byte。

C. 字节流也具有缓冲区:

BufferedInputStream(字节读取缓冲区)和BufferedOutputStream(字节写入缓冲区)。方法与字符缓冲区相似。



原创粉丝点击