今天主要分享的知识点是java中的IO流。我们直接进入正题。C_0006.gif


一.什么是IO流

   所谓流,就是程序与文件之间的通道,它有一个源端和一个目的端,源端和目的端可以是内存的一段区域也可以是磁盘上的某些文件。

二.IO流的分类

1.根据流的方向分(输入与输出都是按程序来说的):

   输入流——从文件流向程序

   输出流——从程序流向文件

2.根据流的数据的单位分:

   字节流——以字节为单位读取流中的数据

            (InputStream抽象类和OutputStream抽象类)

   字符流——以字符为单位读取流中的数据

            (Reader抽象类和Writer抽象类)

3.根据流的功能分:

   节点流

   处理流

三.IO流的相关类简单列出如下表格


输入流输出流

InputStream(字节流)OutputStream(字节流)
基本流(低级流/节点流)



FileInputStream



FileOutputStream

包装流(高级流)DataInputStreamBufferedInputStreamDataOutputStreamBufferedOutputStream


读入流写入流
Reader(字符流)Writer(字符流)
InputStreamReaderBufferedStreamReaderOutputStreamWriterBufferedStreamWriter
FileReader
FileWriter


四.以下详细说明每一对IO字节流类的基本用法

(一).InputStream和OutputStream

1.InputStream抽象类提供了如下几个常用的方法:

(1)int read()读取一个字节以整数形式返回,如果返回-1已到输入流的末尾

(2)read(byte[] b) 一次读入尽可能多的字节去填满字节数组b,返回实际读到的字节数,-1表示已读不到

(3)read(byte[] b, int off, int len) 一次读入尽可能多的字节去填满字节数组boff开始的len个空间

(4)void close()关闭流释放内存资源

(5)long skip(long n)跳过n 个字节不读

2.InputStream抽象类提供了如下几个常用的方法:

(1)void write(int b) 向输出流写入一个字节数据

(2)void flush() 将输出流中缓冲的数据全部写出到文件中


(二)基本流FileInputStream和FileOutputStream——用于象文件中输入输出字节

   用下面的例子说明其使用方法以及一些基本方法的使用:

package io;
/*
 * 对文件简单的操作
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FISFOS_Test {
    public static void main(String[] args) throws IOException {
        //输入流文件必须存在。或者报文件找不到异常。
        File file=new File("d:\\a.txt");
        InputStream is=new FileInputStream(file);
        //读入一个字节并返回
        int i=is.read();
        System.out.println(i);
        //返回一次性读到的字节数
        byte[] b=new byte[10];
        int length=is.read(b);
        System.out.println(length);
        //输出流:自己会新建一个文件
        // true表示追加 false表示覆盖 默认是false     
        OutputStream os=new FileOutputStream(file,true);
        os.write(97);
        //关闭字节流
        is.close();
        os.close();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    }
}

通过上面的例子我们可以再延伸一点,实现文件的复制:


package io;
/*
 * 简单的文件复制操作
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopy {
    public static void main(String[] args) throws IOException {
        copyFile("d:\\照片.rar","d:\\照片(副本).rar");
    }
    public static void copyFile(String file1,String file2) throws IOException{
        FileInputStream fis = new FileInputStream(new File(file1));
        FileOutputStream fos = new FileOutputStream(new File(file2));
        int b = 0;
        //通过定义数组实现每次读取和写入8Byte的数据,加快读写速度
        byte[] arrByte = new byte[8*1024];
        // 读源文件,将读入的每个字节依次写入目标文件即可。
        while((b=fis.read(arrByte))!=-1){
            fos.write(arrByte,0,b);
        }
        fis.close();
        fos.close();
    }
}



(三).缓冲字节流:BufferedInputStream和BufferedOutputStream

  ——把输入输出的字节流先存入到缓冲区中,再一次性的送到磁盘上的文件里

   同样实现文件的复制过程,代码如下:

package io;
/*
 * 用缓冲流实现文件的复制过程
 * 循环里虽然也是一个一个的字节写入缓冲区
 * 但是由于操作内存速度比磁盘快得多
 * 所以可以明显的看到复制过程快于一个一个字节的写入到文件
 */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BISBOS {
    public static void main(String[] args) throws IOException {
        File file1=new File("d:\\照片.rar");
        FileInputStream fis = new FileInputStream(file1);
        BufferedInputStream bis = new BufferedInputStream(fis);
        //下面是另一种创建方法
        //BufferedInputStream bis=new BufferedInputStream(new FileInputStream(new File("d:\\照片.rar")));
        File file2=new File("d:\\照片(副本).rar");
        FileOutputStream fos = new FileOutputStream(file2);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
        int i = 0;
        while((i=bis.read())!=-1){
            bos.write(i);
            // flush不要放在循环中,不然没意义,相当于一个字节一个字节的写。
        }
        // 如果缓冲区满了,自动写入文件
        bos.flush();// 冲刷缓冲区,强制将缓冲区中的内容写入文件
        bos.close();// close关闭之前,先flush。
    }
}


(注意:对于包装类,关闭时只关闭最外层流即可,外层流提供自动关闭其内部的流)


(四).数据字节流:DataInputStream和DataOutputStream

   ——提供了对八种基本数据类型的数据流的读写

1.DataInputStream类的主要方法如下(具体可参见API文档):

(1)read(byte[] b)

            从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。

(2)readBoolean()
         读取一个输入字节,如果该字节不是零,则返回 true,如果是零,则返回 false

(3)readByte()
         读取并返回一个输入字节。

(4)readChar()
         读取两个输入字节并返回一个 char 值。

(5)readDouble()
         读取八个输入字节并返回一个 double 值。

(6)readFloat()
         读取四个输入字节并返回一个 float 值。

(7)readInt()
         读取四个输入字节并返回一个 int 值。

(8)readLong()
         读取八个输入字节并返回一个 long 值。

(9)readShort()
         读取两个输入字节并返回一个 short 值。

(10)readLine()
         从输入流中读取下一文本行。(这个方法已过时,具体使用在下面的BufferedReader字符流中会讲解)

(11)readUTF()
         读入一个已使用 UTF-8 修改版格式编码的字符串。(通常用于网络程序的传输)。

2.DataOutputStream类的方法与DataInputStream类的方法基本一一对应,不过多说明

3.下面通过一个例子说明其中readDouble()方法和writeDouble()方法的使用:

package io;
/*
 * 数据字节流的简单使用
 */
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DISDOSTest {
    public static void main(String[] args) throws IOException{
        File file=new File("d:\\a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        DataOutputStream dos = new DataOutputStream(fos);
        //向文件中写入小数和utf编码的汉字
        dos.writeDouble(3.14);
        dos.writeUTF("中国");
                                                                                                                                                                                                                                                                                                                                                  
        FileInputStream fis = new FileInputStream(file);
        DataInputStream dis = new DataInputStream(fis);
        //读取数据
        double d = dis.readDouble();
        String s = dis.readUTF();
        //小数只能在控制台上显示,在文件里显示的是乱码
        System.out.println(d);
        //汉字以UTF编码可以显示,其他编码也是乱码
        System.out.println(s);
                                                                                                                                                                                                                                                                                                                                                  
        dos.close();
        dis.close();
    }
}


4.学到此时,我们可以利用BufferedInputStream与DataInputStream的结合使用实现对小数的快速读/写,例子代码如下:

package io;
/*
 * 如何快速写小数
 * BufferedOutputStream/DataOutputStream/FileOutputStream
 * 把小数小写到缓冲区再一次性写到文件中
 */
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class DISDOS_Double {
    public static void main(String[] args) throws IOException {
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("d:\\c.txt"))));
        out.writeDouble(3.1415);
        // 对于包装流,关闭时候只关闭外层流就可以了,外层流中有对内层流的关闭。
        out.close();
    }
}



五.以下详细说明每一对IO字符流类的基本用法

(一).Reader和Writer作为字符流的抽象类(方法不再缀余);

(二).InputStreamReader和OutputStreamWriter

           FileReader和FileWriter

           都是用于实现与编码有关的字符流读写。

         (1)FileReader=InputStreamReader+FileInputStream;

         (2)FileWriter=OutputStreamWriter+FileOutputStream;

(注意:当仅仅使用FileReader/FileWriter时只能用默认的编码,并且不能包装其他流;但用后两者结合时可以自己选择使用编码格式)

           这部分的例子如下面的代码:

package io;
/*
 * 使用InputStreamReader+FileInputStream
 * 和OutputStreamWriter+FileOutputStream的读写
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class BianMa {
    public static void main(String[] args) throws IOException {
        File file = new File("d:\\b.txt");
        FileInputStream fis = new FileInputStream(file);
        InputStreamReader isr = new InputStreamReader(fis,"gbk");// 自己选择编码方式
        // 对于汉字来说,gbk/gb2312占两个字节,utf-8占三个字节。
        char i = (char)isr.read();
        System.out.println(i);
                                                                                                                                              
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
        osw.write("中国");
        //下面的代码是用来写入所有以gbk编码格式的字符,有汉字等
        //for(int k=0;k<60000;k++){
        //osw.write(k);
        //}
        osw.close();
        fis.close();
    }
}


package io;
/*
 * 使用FileReader和FileWriter实现的读写
 * 功能与上面的一样
 * 唯一区别:只能使用系统默认的编码方式
 */
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FRFW {
    public static void main(String[] args) throws IOException {
        // 系统默认编码
        File file = new File("d:\\b.txt");
        FileReader fr = new FileReader(file);
        char ch = (char) fr.read();
        System.out.println(ch);
                                                                                                                                           
        // 区别 1.不能指定编码格式,按系统编码格式。2.不能包装其他流
        FileWriter fw = new FileWriter(file);
        fw.write("一二三四五\r\n");
        fw.write("六七八九十");
        fr.close();
        fw.close();
    }
}


(三).BufferedReader和BufferedWriter

   主要注意一个新的方法readLine()参加下列代码的使用:

package io;
/*
 * 重点学会使用readLine()方法
 */
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class BRBW {
    public static void main(String[] args) throws IOException {
        File file = new File("d:\\b.txt");
        //两次包装
        FileInputStream fis = new FileInputStream(file);
        InputStreamReader isr = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(isr);
        String str = null;
        str = br.readLine();//读一行字符
        System.out.println(str);
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write("一二三四五");
        bw.newLine();// 新起一行。输出一个换行符
        bw.write("六七八九十");
        bw.flush();// 注意冲刷
        bw.close();
        isr.close();
    }
}

(四).PrintStream

    PrintStream中的println()经常与BufferedReader中的readline()一起使用;

    在Scanner出现之前,也用于实现从控制台输入一行字符;

    使用实例如下:

package io;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
/*
 * PrintStream中的println()经常与BufferedReader中的readline()一起使用
 * 作用分别是写一行(根据是否重定向来确定写到控制台还是指定的文件中)和读一行
 */
public class SISO {
    public static void main(String[] args) throws IOException {
        InputStream is=System.in;
        InputStreamReader isr=new InputStreamReader(is);
        BufferedReader br=new BufferedReader(isr);
        String str=br.readLine();
        System.out.println(str);
                                                                        
        File file =new File("d:\\g.txt");
        PrintStream ps=new PrintStream(file);
        ps.println("Hello");//向文件中写一行
        System.out.println("控制台:hello");
        System.setOut(ps);//输出重定向,写到ps指定的文件中
        System.out.println("文件:Hello World");
        ps.close();
    }
}

   

   控制台输出:

hello
hello
控制台:hello

   g.txt文件中写入:

Hello
文件:Hello World



关于IO流的相关知识,今天就先说到这里,还剩下一部分相关知识也是很重要的知识——对象序列化,我们明天不见不散C_0019.gif