Java的I/O流基础(输入输出流)

1 什么是流?

流是个抽象的概念,是对输入输出设备的抽象,输入流可以看作一个输入通道,输出流可以看作一个输出通道。
输入流是相对程序而言的,外部传入数据给程序需要借助输入流。
输出流是相对程序而言的,程序把数据传输到外部需要借助输出流。
数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。

2流的分类

在Java程序中,要想从文件中读取数据,需要在程序和文件之间建立一条数据输入的通道,这样程序就可以从文件中读取数据了;反之,如果要在Java程序中把数据写入到文件中,也需要在程序和文件之间建立一条数据输出的通道。当程序创建输入流对象时,Java会自动建立这个数据输入通道,而创建输出流时,Java也会自动建立这个数据输出通道。如下图所示:
Java的I/O流基础(输入输出流)
输入流是从文件读取数据,是一个拉取数据的过程;输出流是将数据写入到文件,是一个推送数据的过程。
输入流和输出流按读取和写入的数据单位可分为字节流和字符流,字节流是以字节为单位传输数据的流,字符流是以字符为单位传输数据的流。
Java所提供的输入流和输出流类封装在Java.io包中,Java输入输出流的体系结构如下图所示:

Java的I/O流基础(输入输出流)

3字节流

字节流:可以从或向一个特定的方向读写数据,数据是字节,通常字节流被称之为低级流。
封装流/处理流:针对字节流进行封装,即对一个已经存在的流进行封装,通过所有的封装流能够对数据更有效的读写,封装流的底层还是字节流,处理流被称之为高级流或过滤流

3.1 InputStream
InputStream 是所有的字节流的父类,其定义了基础的读取方法,它以字节为单位从数据源中读取数据,其派生的常用子类说明如下:
● FileInputStream类
该类以字节为单位从文件中读取数据。
● ByteArrayInputStream类
该类在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中。
● ObjectInputStream类
该类从输入流读入对象,读取对象信息。
● BufferedIutputStream类
缓冲输入流内部维护一个缓冲区,每当我向该流读入数据,都会先将数据存入缓冲区, BufferedInputStream的read方法会从缓冲区去读取数据,当缓冲区全都读取完毕,如果再次read的时候,会在一次把缓冲区填满,read在逐一从从缓冲区中读取数据,以此往复
3.2 Inputstream类中的常用方法:
  (1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
  (2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
  (3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
  (4) public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,
  (5) public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取
  (6) public int close( ) :我们在使用完后,必须对我们打开的流进行关闭
3.3 OutputStream
OutputStream是所有的字节流的父类,其定义了基础的写出方法,它以字节为单位将数据写入数据源,其派生的常用子类说明如下:
● FileOutputStream类
该类以字节为单位将数据写入到文件。
●ByteArrayOutputStream类
该类在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。
●ObjectOutputStream类
该类将对象信息写入到输出流。
● BufferedOutputStream类
缓冲输出流内部会维护一个缓冲区,每当我们向该流写出数据时,都会先将数据存入缓冲区,当缓冲区已满的时候,缓冲流会将数据一次性写出
3.4 Outputstream类中的常用方法:

  1. public void write(byte b[ ]):将参数b中的字节写到输出流。
      2. public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
      3. public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
      4. public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
      5. public void close( ) : 关闭输出流并释放与流相关的系统资源。

4字符流Writer/Reader

Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。
4.1 Reader抽象类
是所有字符流的父类,是一个抽象类。常用子类如下
●InputStreamReader类:字符输入流
可以设置字符集,按照指定的字符集输入数据,将字节按照指定的字符集读入字符串数据
●FileReader
主要用来读取字符文件,与FileInputStream对应
●BufferedReade
缓冲字符流输入
4.2 主要方法
(1) public int read() throws IOException; //读取一个字符,返回值为读取的字符
  (2) public int read(char cbuf[]) throws IOException; /读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量/
  (3) public abstract int read(char cbuf[],int off,int len) throws IOException;
  /读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现/
4.3 Writer抽象类:
是所有字符流的父类,是一个抽象类。常用子类如下
●OutputStreamWriter类:字符输出流
可以设置字符集,按照指定的字符集输出数据,将字节按照指定的字符集写出字符串数据
● FileWrite:
将字符类型数据写入文件,与FileOutputStream对应
●BufferedWriter
缓冲字符流输出
4.4 主要方法:
  (1) public void write(int c) throws IOException; //将整型值c的低16位写入输出流
  (2) public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流
  (3) public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流
  (4) public void write(String str) throws IOException; //将字符串str中的字符写入输出流
  (5) public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流
  (6) flush( ) //刷空输出流,并输出所有被缓存的字节。
  (7)close() 关闭流 public abstract void close() throws IOException

5 IOException常见异常

1.public class EOFException :
非正常到达文件尾或输入流尾时,抛出这种类型的异常。
2.public class FileNotFoundException:
当文件找不到时,抛出的异常。
3.public class InterruptedIOException:
当I/O操作被中断时,抛出这种类型的异常。