Java IO流

Posted on 2016-06-30 22:05  artzok  阅读(84)  评论(0)    收藏  举报

在计算机编程中,IO是一项非常重要的内容。I表示Input,O表示Output,即输入/输出。这里所说的输入/输出都是站在应用程序的立场上讲的。输入和输出都必须有目标,对于输入,目标就是程序本身,可能是文件、网络、内存空间、数据库等等。对于输出,上述情况刚好相反。

一 、流的概念

流(stream)的概念源于UNIX中管道(pipe)的概念。在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备、外部文件等。

一个流,必有目标,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL。
流的方向是重要的,根据流的方向,流可分为两类:输入流和输出流。用户可以从输入流中读取信息,但不能写它。相反,对输出流,只能写,而不能读。

实际上,流的目标可以简单地看成字节的生产者和消费者,对输入流,可不必关心它的是什么,只要简单地从流中读取数据即可;对于输出流,也不需要知道它的目标,只是简单地往流中写数据即可。

我们可以将IO流形象的比喻为水流,文件和程序属于水流的两个端点,他们之间连接着一条管道,此时,水流就在他们之间形成了,自然也就出现了方向:可以流进,也可以流出。

二 、Java IO流的分类

如果根据IO的流向分类,当然只有两种了:输入流输出流

如果依据操作数据的类型分类,可以分为:字节流字符流

按照功能划分的话,可以分为:节点流包装流

下面截图展示了Java 的四大基本IO流,并且对应着四个抽象类:
Java IO 四大基本流

三、Java常用IO流

上面介绍了Java中的四大基本IO流,这四大基流在Java中对应四个抽象类,每个抽象类都定义了属于这种流的规范操作。由于是抽象类,因此我们不能实例化任何对象,要进行IO操作,就必须使用上述四大基流的继承类。根据功能和类型,Java中常用IO流的操作类包含以下几种:

JAVA IO FRAME

上面列举了Java中各种常用的IO操作类。其中,字节流表示IO操作时以字节为基本单位, 一般用于操作二进制的文件或数据,也可以操作纯文本数据。字符流表示以字符为单位进行IO操作,只能用于纯文本文件或数据的操作。文件流表示IO操作的目标是文件。数组/内存流表示IO操作的目标是内存中的数组对象。文件流和数组/内存流都属于节点流包装流表示对节点流的二次封装,用于更为特殊的目的,比如缓冲流用于加速节点流的IO操作。转换流用于将字节流转换为字符流。合并流用于将多个字节流合并为一个连续的字节流。

四、常用IO类的使用

上面讲了这么多概念只为了帮助自己和大家理解、记忆。下面结合一个经典案例,讲讲上述这些IO类的使用方法。

案例:文件拷贝(文本文件、二进制文件、多个文本文件合并)。

1. 使用文件流实现拷贝
a. 字节流实现

public static void fileCopyByByte() {
        // 1 输入源和输出目标(一般用于操作二进制文件)
        File src = new File("srcFolder/something.avi");
        File dest = new File("destFolder/something.avi");
        
        try(// java7新增语法
	        // 2 流对象
	        InputStream in = new FileInputStream(src);
	        OutputStream out = new FileOutputStream(dest);
        ) {
            // 3 拷贝操作
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

b. 字符流实现

    public static void fileCopyByChar() {
        // 1 输入源和输出目标(只能操作文本文件)
        File src = new File("srcFolder/something.txt");
        File dest = new File("destFolder/something.txt");
        try(
	        // 2 流對象
	        Reader reader = new FileReader(src);
            Writer writer = new FileWriter(dest);
        ) {
            // 3 拷贝操作
            char[] buffer = new char[1024];
            int len = 0;
            while ((len = reader.read(buffer)) > 0) {
                writer.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2.使用缓冲流加速IO操作
a.字节缓冲流实现

public static void fileCopyByByteBuffer() {
    // 1 输入源和输出目标(一般用于操作二进制文件)
    File src = new File("srcFolder/something.avi");
    File dest = new File("destFolder/something.avi"); 
    try (
	    // 2 流对象
	    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(src));
		BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(dest));
	) {
        // 3 拷贝操作
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = bin.read(buffer)) > 0) {
            bout.write(buffer, 0, len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

b. 字符缓冲流实现

public static void fileCopyByCharBuffer() {
    // 1 输入源和输出目标(只能操作文本文件)
    File src = new File("srcFolder/something.txt");
    File dest = new File("destFolder/something.txt");
    try (
		// 2 流对象
		BufferedReader br = new BufferedReader(new FileReader(src));
        BufferedWriter bw = new BufferedWriter(new FileWriter(dest));
    ) {
        // 3 拷贝操作
        char[] buffer = new char[1024];
        int len = 0;
        while ((len = br.read(buffer)) > 0) { 
            bw.write(buffer, 0, len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3. 合并流、转换流、缓冲流综合实例:将多个文本文件拷贝到另一个文件

public static void megreIO() {
    // 1 输入源和输出目标
    File src1 = new File("srcFolder/a.txt");
    File src2 = new File("srcFolder/b.txt");
    File dest = new File("destFolder/dest.txt");
    // 2 流對象
    try (
         InputStream sis = new SequenceInputStream(
	         new FileInputStream(src1), new FileInputStream(src2));
         BufferedReader reader = new BufferedReader(new InputStreamReader(sis));        
         BufferedWriter writer = new BufferedWriter(new FileWriter(dest));
    ) { 
        // 3 拷貝操作
        String str = null;
        while ((str = reader.readLine()) != null) { // 字符缓冲流增加了读取一行的操作方法
            writer.write(str);
            writer.newLine(); // 写入换行
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

五、安全关闭

上面介绍的几个实例都使用了Java7新增的语法。在Java7之前我们必须使用下面方法安全的关闭资源(包括socket、文件、数据库等):

    public static void fileCopyByByte() {
        // 1 源和目标
        File src = new File("srcFolder/something.avi");
        File dest = new File("destFolder/something.avi");
        InputStream in = null;
        OutputStream out = null;
        try {
            // 2 流對象
            in = new FileInputStream(src);
            out= new FileOutputStream(dest); 
            // 3 拷贝操作
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(in != null) {
                    in.close();
                }
            } catch (IOException e2) {
                e2.printStackTrace();
            }
            
            try {
                if(out != null) {
                    out.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

由于语法过于繁琐,Java7实现了自动关闭资源的方法,在该方法中我们只需要将资源对象的创建代码放在try catch语句的声明列表中即可。但是,只有实现了java.lang.AutoCloseable接口的资源类才能使用自动关闭,一般的文件、数据库连接等均已实现该接口,该接口的实现方法将调用资源对象的close()方法关闭资源。利用自动关闭,上述代码就变得非常简洁了:

    public static void fileCopyByByte() {
        // 1 源和目标
        File src = new File("srcFolder/something.avi");
        File dest = new File("destFolder/something.avi");
        
        try (
        // 2 流對象
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dest);
        ) {
            // 3 拷贝操作
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3